HMR
HMR:模块热替换,可以在运行的时候,不刷新页面,直接更换与删除模块
webpack4
-
plugins: [ new webpack.DefinePlugin({ 'process.env': require('../config/dev.env') }), // 开启全局的 HMR 能力 new webpack.HotModuleReplacementPlugin(), ]
-
开发环境开启HMR
devServer: { //开启HMR hot:true },
webpack5默认开启了HMR
Source-map
source-map:一种提供源代码到构建后代码的映射技术(如果构建后代码出错了,可以通过映射追踪代码出错位置)
最常用的三种:[inline-|hidden-|eval-]source-map
不常用的:[nosources-|cheap-[module]]source-map
内联:inline-、eval-
外部:source-map、hidden-、nosources-、cheap-[module]
- source-map:错误代码准确信息 和 源代码的错误位置
- inline-source-map:错误代码准确信息 和 源代码的错误位置
- hidden-source-map:错误代码的错误原因,但是没有错误位置,不能追踪源代码错误,只能提示到构建后代码的错误位置
- eval-source-map:错误代码的准确信息 和 源代码的错误位置
- nosource-source-map:错误代码准确信息,但是没有任何源代码
- cheap-source-map:错误代码的准确信息 和 源代码的错误位置,只能精确到行
- cheap-module-source-map:错误代码的准确信息 和 源代码的错误位置
source-map选择:
-
开发环境:速度快,调试友好
速度:eval>inline>cheap…
-
eval-cheap-source-map
-
eval-source-map
调试友好:
-
source-map
-
cheap-module-source-map
-
cheap-source-map
–>eval-source-map
–>eval-cheap-module-source-map
-
-
生产环境:源代码要不要隐藏 调试
内联会让代码体积十分庞大,所以在生产环境中不考虑使用内联
–>source-map
–>cheap-module-source-map
–>hidden-source-map
oneOf
rules: [
{
// js兼容性
test: /\.js$/,
exclude: /node_module/,
loader: "babel-loader",
options: {
// 预设:指示babel怎么做兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: "usage",
corejs: {
version:3
},
}
]
]
}
},
{
// 一下loader只会匹配一个
// 一个类型的文件只会被处理一次
//所以js文件需要单独提取出来
oneOf: [
{
// css
test: /\.css$/,
use: [...commonCssLoader]
},
{
// less
test: /\.less$/,
use: [...commonCssLoader,"less-loader"]
},
/*
当一个文件被多个laoder处理时,要指定loader执行的先后顺序
*/
{
// js
test: /\.js$/,
exclude: /node_module/,
// 优先执行
enforce:'pre',
loader: "eslint-loader",
options: {
fix:true
}
},
]
}
]
缓存
babel缓存
babel缓存会使第二次打包构建速度更快
rules:[
{
// js兼容性
test: /\.js$/,
exclude: /node_module/,
loader: "babel-loader",
options: {
// 预设:指示babel怎么做兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: "usage",
corejs: {
version:3
},
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存,加快构建速度
cacheDiretory:true
}
},
]
文件资源缓存
给文件名加上hash值
- hash:每次修改打包后会给新的hash值
- js和css使用同一个hash值,重新打包会使所有缓存失效
- chunkhash:根据chunk生成的hash值
- 如果打包来源于同一个trunk,那么hash值一样
- contenthash:根据文件内容生成hash值
- 不同文件的contenthash一定不同
文件资源缓存使代码上线运行缓存更好使用
tree shaking
使用前提:
- 必须使用es6模块化
- 开启production环境
作用:减少代码体积
在package.json中配置sideEffects
sideEffects:false 所有代码都没有副作用(都可以进行tree shaking)可能会把css/@babel/polyfill…文件干掉
推荐自己设置sideEffects
{
"sideEffects":["*.css","*.less",...]
}
code split
-
多入口
module.exports={ entry: { main: "./src/js/index.js", test: "./src/js/test.js", }, }
webpack会按照入口生成对应的built.js
-
optimization.splitChunks
/* 1.可以将node_module中代码单独打包一个chunk最终输出 2.自动分析多入口chunk中,有没有公共文件。如果有,会打包成一个单独的chunk */ optimization: { splitChunks: { chunks:"all" } },
-
import
/* 通过js代码,让某个文件被单独打包成一个chunk import动态导入语法:能将某个文件单独打包 单入口y */ import(/* webpackChunkName:'test' */ './test').then((result) => { console.log("文件加载成功",result); }).catch(() => { console.log("文件加载失败"); })
lazyload&preload
//通过异步函数,来动态加载
document.querySelector("#btn").onclick = function () {
// 懒加载
import(/* webpackChunkName:'test'*/'./test').then(({mul}) => {
console.log(mul(2,3));
})
// 预加载 prefetch:会在使用之前,提前加载js文件
//预加载存在兼容性问题
import(/* webpackChunkName:'test',webpackPrefetch:true*/'./test').then(({mul}) => {
console.log(mul(2,3));
})
}
PWA
PWA:离线访问技术,也就是当我们没有网络的时候也可以访问(有限资源)
- 安装 workbox-webpack-plugin 插件
npm i workbox-webpack-plugin -D
- 配置
//webpack.config.js
const WorkboxWebpackPlugin =require("workbox-webpack-plugin")
plugins:[
new WorkboxWebpackPlugin.GenerateSW({
/*
1.帮助serviceworker快速启动
2.删除旧的serviceworker
组测serviceworker
*/
clientsClaim: true,
skipWaiting:true
})
]
- 注册serviceworker
//src/js/index.js 也就是你的入口文件
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(() => {
console.log('sw 注册成功');
}).catch(() => {
console.log('sw注册失败');
});
});
}
- 使用
serviceWorker必须运行在服务器上所以可以自己用node.js搭建一个本地服务器
或者 使用 serve 第三方库快速搭建
在项目根目录键入以下指令,可以快速搭建一个本地服务器
npm i serve -g
serve -s build
serve -s build 启动服务器,将build目录下的所有资源全部暴露出去
多进程打包
使用多进程打包需要安装 thread-loader
npm i thread-loader -D
使用多进程打包时候需要考虑你的项目是否真的需要多进程打包。
进程启动大概600ms,进程通信也有开销,只有工作消耗时间比较长才需要多进程打包。
所以使用不恰当可能会使构建速度下降,我们要谨慎使用
modules:{
rules:[
{
//babel中比较适合使用多进程打包
// js兼容性
test: /\.js$/,
exclude: /node_module/,
use: [
/*
开启多进程打包
进程启动大概600ms,进程通信也有开销
只有工作消耗时间比较长才需要多进程打包
*/
{
loader: 'thread-loader',
options: {
workers:2//2个进程
}
},
{
loader: "babel-loader",
options: {
// 预设:指示babel怎么做兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: "usage",
corejs: {
version:3
},
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory:true
}
}
],
}
]
}
externals
使用externals可以拒绝一些第三方包参与构建
module.exports={
externals: {
// 库名:npm包名
jquery:"jQuery"
}
}
dll
使用dll技术对某些库(第三方库:jquery,react,vue…)单独打包,避免第三方库重复打包,可以在第一次打包之后提高构建效率
//新建 webpack.dll.js
const { resolve } = require("path");
const webpack = require("webpack");
module.exports = {
entry: {
/*
暴露的库名(自定义):tdLib,
需要暴露的库:["jquery",......]
*/
tdLib:["jquery"]
},
output: {
filename: '[name].js',
path: resolve(__dirname, "dll"),
library:'[name]_[hash]',//打包的库向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个mainfest.json-->提供和jquery的映射
new webpack.DllPlugin({
name: '[name]_[hash]',//映射库的暴露的内容名称
path:resolve(__dirname,'dll/mainfest.json')//输出文件路径
})
],
mode:"production"
}
运行 webpack.dll.js
webpack --config webpack.dll.js
运行之后会发现多出了一个dll目录,该目录中就包含打包的第三库以及与其对应的映射关系。
然后我们接着需要在webpack.config.js中做相应配置,然后正常打包就行。
npm i add-asset-html-webpack-plugin -D
//webpack.config.js
const webpack =require("webpack")
const AddAssetHtmlWebpackPlugin =require("add-asset-html-webpack-plugin")
module.exports={
plugins: [
// 告诉webpack那些库不参与打包,同时使用时的名称也得变
new webpack.DllReferencePlugin({
manifest:resolve(__dirname,"dll/mainfest.json")
}),
// 会将某个文件打包输出出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,"dll/tdLib.js")
})
],
}