Webpack性能优化
一、理想目标
- 初始化 js <= 200kb
- 初始化 css <= 100kb
- http1.1 <= 6个请求
- http2.0 <= 20个请求
- 更高的代码已使用率,更低的代码未使用率
二、查看代码已使用率
在 Chrome 浏览器的开发者工具中查看。
1. 京东(已用68%)
2. 淘宝(已用52%)
淘宝还有很大的优化空间。
三、代码分离(静态导入)
1. 配置多个入口文件
// webpack.config.js
module.exports = {
entry: {
index1: './src/index.js',
index2: './src/index2.js'
}
}
2. 配置输出文件名字(便于区分)
// webpack.config.js
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
}
}
四、代码分离(动态导入,按需加载)
为了减少初始化 js 的大小,有些模块一开始不需要引入,只有在需要它的时候才引入。例如,按钮的点击事件,点击时才加载需要的模块。
1. 需求
点击 html 中的按钮时,切换按钮的字体颜色。
// button.js 生成一个按钮
export default function makeBtn() {
let btn = document.createElement('button');
let body = document.getElementsByTagName('body')[0];
btn.innerHTML = '我是一个Btn!';
body.appendChild(btn);
}
// color.js
let colorRed = 'red';
let colorBlue = 'blue';
export {
colorRed,
colorBlue
}
2. 模块引入
// 入口文件 index.js
import makeBtn from './button.js'
makeBtn(); // 生成按钮
let btn = document.getElementsByTagName('button')[0];
3. 静态导入
import {colorRed, colorBlue} from './color.js'
btn.onclick = function () {
this.style.color = (this.style.color === colorRed ? colorBlue : colorRed);
}
4. 动态导入
btn.onclick = function () {
// 动态导入,按需导入
import('./color.js')
.then(res => {
this.style.color = (this.style.color === res.colorRed ? res.colorBlue : res.colorRed);
})
}
只有在触发了 btn 的点击事件时,才会引入 color 模块。
5. 动态导入的 loader 配置
这里因为使用了动态语法可能会涉及动态 import 的兼容问题,需要安装依赖和配置。
npm i @babel/plugin-syntax-dynamic-import
https://blog.csdn.net/m0_37616866/article/details/85601201
五、动态导入的优化写法
将 import(...) 写在顶部,优化代码。
// 入口文件 index.js
const getColor = () => {
return import('./color.js')
}
// 进一步优化为:
const getColor = () => import('./color.js')
使用,通过 getColor() 调用,相当于原来的写法。
btn.onclick = function () {
getColor().then(res => {
this.style.color = (this.style.color === res.colorRed ? res.colorBlue : res.colorRed);
})
}
六、动态导入的其他形式
1. 导入第三方库
例如,动态导入lodash工具库。
const getLodash = () => import('lodash-es')
注意要安装依赖 lodash-es,这是es6版本的 lodash。
npm i lodash-es --save-dev
2. 导入文件夹中所有模块
(1)在 scr 下新建文件夹 buttonBgc,里面放着三种颜色。
// bgcA.js
export default {
color: '#ccc'
}
// bgcB.js
export default {
color: '#666'
}
// bgcC.js
export default {
color: '#eee'
}
(2)导入文件
const getBgc = (bgc) => import(`./buttonBgc/${bgc}.js`)
btn2.onclick = function () {
getBgc('bgcB').then(res => {
// console.log(res.default)
this.style.backgroundColor = res.default.color
})
}
现在传进去的是 bgcB 的颜色。
(3)打包编译
名字非常拉胯,webpack 提供了一个叫做魔法注释的方法去设置他们的名字。
七、Magic Comments
https://webpack.js.org/api/module-methods/#magic-comments
1. webpackChunkName
(1) 使用
const getColor = () => import(/* webpackChunkName: "font-color" */ './color.js')
const getLodash = () => import(/* webpackChunkName: "lodash" */ 'lodash-es')
const getBgc = (bgc) => import(/* webpackChunkName: "bgc-color" */ `./buttonBgc/${bgc}.js`)
(2) 效果
打包编译后:
chunkhash 有点长,可以自定义位数,具体在 output 的 filename 上设置。
2. webpackMode
在开发模式适用 lazy-once 模式。
对于 bgcColor 文件夹下的模块,下面只用到了 bgcB.js 一个模块,因此完全没有必要把那个目录下所有的模块都去打包编译出来。
用了 / webpackMode: "lazy-once" / 就能实现这种功能:只打包用到的模块。
/* webpackMode: "lazy-once" */
// 入口文件 index.js
// 对环境进行判断,从而确定是否使用 lazy-once。如果是开发模式就用lazy-once,否则不用。
// console.log(process.env.NODE_ENV); // node中提供的查看环境的变量
if (process.env.NODE_ENV === 'development') {
const getBgc = (bgc) => import(/* webpackChunkName: "bgc-color" */ /* webpackMode: "lazy-once" */ `./buttonBgc/${bgc}.js`)
} else if (process.env.NODE_ENV === 'production') {
const getBgc = (bgc) => import(/* webpackChunkName: "bgc-color" */ `./buttonBgc/${bgc}.js`)
}
btn2.onclick = function () {
getBgc('bgcB').then(res => {
console.log(res.default)
this.style.backgroundColor = res.default.color
})
}
八、Prefetching/Preloading modules
代码分离中的预加载功能:
https://webpack.js.org/guides/code-splitting/#prefetchingpreloading-modules
有些模块可以让它提前进行加载,以免动态导入时产生延迟,这样就提高了用户体验。
const getColor = () => import(/* webpackChunkName: "font-color" */ /* webpackPrefetch: true */ './color.js')