上篇文章,已经说明了进行优化的前期准备,如何查看构建统计信息、速度分析,以及体积分析。这篇文章就写写,如何进行具体的优化。
1. 构建速度优化
1. 使用高版本工具的福利
高版本的 webpack 和 node.js 能带来构建时间上的提升,以 webpack4 为例。
V8 上的优化,提升了代码执行效率。比如:
for of 替换 forEach | Map 和 Set 替换 Object | Includes 替换 indexOf
默认使用更快的 md4 hash 算法
webpack AST 可以直接从 loader 传递给 AST,减少间隙时间
使用字符串方法替换正则表达式
2. 资源并行解析
这里使用 thread-loader 并行解析资源,大概原理是:每次 webpack 解析一个模块,loader 会将它的依赖分配给 worker 线程处理。用法如下:
module.exports = {
module:{
rules:[
{
test:/.js$/,
include: path.resolve('src'),
use:[
{
loader:'thread-loader',
options:{
// 开启线程数
workers:3,
// 额外的nodejs参数
workerNodeArgs: ['--max-old-space-size=1024']
// 其他更具体参数,查看文档
},
},
'babel-loader'
]
}
]
}
}
复制代码
说明:thread-loader 要放在其他 loader 之前,随后的 loader 将在工作池中运行。每个工作程序都是一个单独的 node.js 进程,其开销约为 600 毫秒,并且进程间通信也有开销,因此这个 loader 只能用于一些昂贵的操作。
3. 并行压缩
使用 parallel-uglify-plugin 插件
const ParallelUglifyPlugin = require('parallel-uglify-plugin')
// 更详细配置查看官网
module.exports = {
plugins:[
new ParallelUglifyPlugin({
uglifyJS:{
output:{
beautify:false,
comments:false
},
compress:{
warning:false,
drop_console:true
}
}
})
]
}
复制代码
使用 uglifyjs-webpack-plugin 插件
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins:[
new UglifyJsPlugin({
parallel:true, // 开启并行
uglifyOptions:{
// 其他配置查看官网
}
})
]
}
复制代码
使用 terser-webpack-plugin 插件
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
optimization:{
minimizer:[
new TerserPlugin({
parallel:3 // 开启并行数
})
]
}
}
复制代码
2. 构建体积优化
1. 分包:设置 Externals
通过 html-webpack-externals-plugins,将一些基础包通过 cdn 引入,不打入 bundle。
const HtmlWebpackExternalsPlugins = require('html-webpack-externals-plugins')
module.exports = {
new HtmlWebpackExternalsPlugins({
externals:[
{
module:'vue',
entry:'//***/vue.min.js',
global:'Vue'
}
]
})
}
复制代码
这种方式构建完成后,会在 index.html 创建多个 script 标签,分别引入对应的库(配置的 entry).
2. 分包:预编译资源模块
思路:将基础包(react/react-dom 等)和业务基础包打包成一个文件
方法:使用 DLLPlugin 插件进行分包,DllReferencePlugin 对 maniffest.json 引用
实现流程如下:
根目录编写配置文件:webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const library = {
vue: ["vue", "vue-router", "vuex"], // 值越多,抽取的文件越大,键为抽取的文件名
others: ["axios", "js-cookie"],
}
// dll文件存放的目录
const dllPath = "public/baselib";
module.exports = {
// 入口文件
entry: {
...library
},
// 输出文件
output: {
path: path.join(__dirname, dllPath),
filename: "MyDll.[name].js",
library: "[name]_[hash]"
},
plugins: [
// 清除上一打包产生的dll文件
new CleanWebpackPlugin(),
new webpack.DllPlugin({
path: path.join(__dirname, dllPath, "[name]-manifest.json"),
name: "[name]_[hash]"
})
]
};
复制代码
package.json 添加打包命令
{
"scripts":{
"dll":"webpack -p --progress --config ./webpack.dll.conf.js"
}
}
复制代码
执行命令,产生文件
执行命令:npm run dll
,会产生如下文件
public/baselib/vue-manifest.json
public/baselib/others-manifest.json
public/baselib/MyDll.vue.js
public/baselib/others.js
webpack 配置 DllReferencePlugin
const path = require("path");
const webpack = require("webpack");
const dllPath = "./public/baselib/";
// 应当处理出公共配置
const library = {
vue: ["vue", "vue-router", "vuex"],
others: ["axios", "js-cookie"],
}
plugins: [
...Object.keys(library).map(name => {
return new webpack.DllReferencePlugin({
context: ".",
manifest: path.join(dllPath, `${name}-manifest.json`)
});
})
]
复制代码
模板文件引入 js
<body>
<!--文件路径中<%= BASE_URL %>为vue cli 3中读取根目录的写法,使用其他框架的请使用自己的写法-->
<script src="<%= BASE_URL %>baselib/MyDll.vue.js"></script>
<script src="<%= BASE_URL %>baselib/MyDll.others.js"></script>
</body>
复制代码
只要运行 np run dll 命令打包一次即可,若配置有更改,则需重新打包以及引入文件。
3. 总结
至此我们完成了 webpack 速度优化和体积优化策略的学习,当然还有设计其他优化策略,下一章继续。
评论