- 分析打包速度:speed-measure-webpack-plugin
- 分析包内容:webpack-bundle-analyzer
- 分析影响打包速度环节:
- 开始打包,我们需要获取所有的依赖模块
- 优化搜索时间:在遇到导入语句时webpack会做两件事
-
- 根据导入语句去寻找对应要导入的文件
-
- 根据找到的要导入的文件的后缀,使用配置中的loader去处理文件。
- 优化loader配置:通过以下配置来命中loader要应用规则的文件
- 优化resolve.module配置:resolve.module用于配置webpack去哪些目录下寻找第三方模块,默认值就是["node_modules"].
- 优化resolve.alias配置:该配置通过别名来把原导入路径映射成一个新的导入路径,减少耗时的递归解析操作
- 优化resolve.extensions配置:在导入语句没带文件后缀时,webpack会根据webpack.extension自动带上后缀去尝试询问文件是否存在,所以在配置resolve.extensions应尽量注意以下几点:
- 高频的后缀放前面
- 不存在的文件后缀情况不要写在里面
- 在源码中写导入语句时,要尽可能的带上后缀,从而避免寻找过程。
- 优化resolve.mainFields配置:有些第三方模块会针对不同环境提供几份代码,例如分别提供采用es5,es6的两份代码,这两份代码的位置写在package.json文件里,webpack会根据mainFields的配置去决定优先采用哪份代码。mainFields默认值如下:["browser","main"]。webpack会按照数组里的顺序去package.json里找,只会使用找到的第一个
{
"jsnext:main": "es/index.js",
"main": "lib/index.js"
}
如果想优先采用es6的那份代码,可以配置为:mainFields:["jsnext:main","browser","main"]
- 优化module.noParse:可以让webpack忽略对部分没采用模块化的文件递归解析处理,能提高构建性能。例如jquery,chartjs,庞大且没采用模块化标准,webpack解析这些文件耗时且没意义。
- 通过loader解析代码,js单线程特性使js/css/图片/字体等文件转换不能并发处理
- 优化解析时间
- 开启多进程打包
- thread-loader:原理是放置在这个loader之后的loader会在一个单独的worker池运行。一个worker就是一个nodejs进程,每个单独进程处理时间上限为600ms,各个进程的数据交换也会限制在这个时间内。但是启动worker是有高延迟的,所以对worker池的优化是预热。仅在耗时的loader上使用。
- 当项目较小时,多进程打包反而会使打包速度变慢
- 将所有依赖模块打包到一个文件,js压缩会先将代码解析成AST语法树,然后再根据复杂的规则去分析和处理AST,最后将AST还原成js,这个过程涉及大量计算,所以会耗时且卡。
- 优化压缩时间
- webpack3启动打包时加上--optimize-minimize,webpack会自动为你注入一个带有默认配置的UglifyJSPlugin(webpack4已废弃)或:
module.exports = {
optimization: {
minimize: true,
},
}
UglifyJSPlugin是单线程,ParallelUglifyJSPlugin插件实现了多进程压缩。它会开启多个子进程,把多个文件的压缩工作分配给多个子进程去完成,每个子进程其实还是通过UglifyJS去压缩代码,但变成了并行执行。
- webpack4:默认内置使用terser-webpack-plugin插件压缩优化代码,而该插件使用terser来缩小js。
为什么webpack选择terser?因为uglify-es不再维护,且uglify-js不支持es6。terser是uglify-es的一个分支,保留了uglify-es和uglify-js@3的API和cli兼容性。
使用多进程并行运行来提高构建速度。并发运行的默认数量为os.cpu().lenght-1。即设置parallel为true。多进程可显著加快构建速度,推荐开启。
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
parallel: true,
}),
],
},
};
- 二次打包,一点小修改就需要重新打包,而且所有文件都需要重新打包,需要浪费初次打包相同的时间,但很多文件没变更
- 优化二次打包时间
- 合理利用缓存(缩短连续构建时间,增加初始构建时间)
- 使用缓存的几种方法有:cache-loader,HardSourceWepackPlugin或babel-loader的cacheDirectory标志。所有这些缓存方法都有启动的开销。重新运行期间在本地节省的时间很大,但是初始(冷)运行实际上会更慢。
- cache-loader:在一些性能开销比较大的loader之前添加此loader,会将结果缓存到磁盘里,显著提升二次构建速度。保存和读取这些缓存文件有一些时间的开销,所以只针对性能开销较大的loader使用此loader。
- HardSourceWebpackPlugin:第一次构建将花费正常的时间。第二次构建将显著加快(大概提升90%)
module.exports = {
module: {
noParse: /jquery/,
rules: [
{
test: /\.(js|jsx)$/,
use: ['babel-loader?cacheDirectory'],
exclude: /node_modules/,
},
]
},
resolve: {
modules: [
path.resolve(`${project}/client/components`),
path.resolve('h5_commonr/components'),
'node_modules'
],
extensions: ['.js', '.jsx', '.react.js', '.css', '.json'],
alias: {
'@compontents': path.resolve(`${project}/compontents`),
}
},
};
参考:
玩转 webpack,使你的打包速度提升 90%