webpack 透视——提高工程化(实践篇)
webpack 是我们前端工程师必须掌握的一项技能,我们的日常开发已经离不开这个配置。关于这方面的文章已经很多,但还是想把自己的学习过程总结记录下来。
上一篇文章介绍了webpack 构建原理,这篇文章将基于这个原理之上,讲述在我们实际工程配置中可以去优化的2 个方向。
- 提升构建速度,也就是减少整个打包构建的时间,
- 优化构建输出,也就是减小我们最终构建输出的文件体积。
1. 提升构建速度
1.1 哪些阶段可以提速?
我们先回顾下整个构建过程,首先从入口文件开始递归生成所有文件的module实例,再针对所有module 实例的依赖关系进行分析优化,划分为一个或多个 chunk 去生成最终的打包文件输出。那哪些阶段我们可以去节约时间呢?
module 实例的优化和处理的时间我们并不好做提速,这里往往涉及到最终输出文件的大小,我们做的优化操作越多,输出的文件体积越小,这是我们希望看到的,所以只能从生成 module 实例阶段去入手提速,在这个阶段文件会经过以下处理:
- resovle阶段: 获取文件所在的绝对路径以及文件要被哪些loaders编译转换
- run-loader阶段:执行对应的 loaders对文件执行编译转换
- parse 阶段:解析文件是否存在依赖,以及对应的依赖文件。
在这个过程中,我们可以节约时间的方向:
- resolve 阶段: 减少查找文件绝对路径的时间
- run-loader阶段: 减少要被 loader 执行编译转换的文件数量
1.2 如何配置?
- resolve 阶段
resolve: {
// 位于 src 文件夹下常用模块,创建别名,准确匹配
alias: {
xyz$: path.resolve(__dirname, 'path/to/file.js')
},
modules: ['node_modules'], // 查找范围的减小
extensions: ['.js', '.json'], // import 文件未加文件后缀是,webpack 根据 extensions 定义的文件后缀进行依次查找
mainFields: ['loader', 'main'], // 减少入口文件的搜索步骤,设置第三方模块的入口文件位置
},
- 充分利用别名,配置别名的路径,可准确匹配到对应文件路径,减少文件查找时间
- 配置 modules,减少文件查找范围
- extensions 配置项要充分利用,在我们引入的文件没有添加后缀信息时,webpack 会遍历此配置项,依次加上配置项数组里的后缀去查找匹配文件,所以在我们日常的开发中最好加上文件后缀,可以省略添加后缀查找的步骤,或者我们把高频的文件后缀放在数组前面,这样通过减少遍历次数去节约时间
- run-loader 阶段
module: {
rules: [
{
test: /\.js$/, // 匹配的文件
use: 'babel-loader',
// 在此文件范围内去查找
include: [],
// 此文件范围内不去查找
exclude: file => (
/node_modules/.test(file) &&
!/\.vue\.js/.test(file)
)
}
]
}
在此阶段要充分利用include和exclude配置项,将需要经过 loader 转换的文件限定在某个范围内,或者把不需要经过此 loader 执行的文件过滤掉。
2. 优化构建输出
减小最终输出的包体积可以从如下几个方向着手:
- tree-shaking
- 代码压缩
2.1 Tree-shaking
Tree-shaking的意思是将我们没有用到的代码剔除掉,从而减少总的打包体积。在 webpack4.0 生产模式中,已默认帮我开启了 tree-shaking,我们先了解下它tree-shaking的原理
// a.js
import {
add
} from './b.js'
add(1, 2)
// b.js
export function add(n1, n2) {
return n1 + n2
}
export function square(x) {
return x * x;
}
export function cube(x) {
return x * x * x;
}
我们可以看到 b.js中的square和cube方法并没有被使用到,我们在开发模式下开启 usedExports的配置,
mode: 'development',
optimization: {
usedExports: true
}
b.js 最后打包的结果如下:
/***/ "./src/chunk/b.js":
/*!************************!*\
!*** ./src/chunk/b.js ***!
\************************/
/*! exports provided: add, square, cube */
/*! exports used: add */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() {
return add;