这是我参与更文挑战的第29天,活动详情查看:更文挑战
[webpack系列文章连载中…]
上篇文章,已经说明了进行优化的前期准备,如何查看构建统计信息、速度分析,以及体积分析。这篇文章就写写,如何进行具体的优化。
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="https://juejin.cn/post/<%= BASE_URL %>baselib/MyDll.vue.js"></script>
<script src="https://juejin.cn/post/<%= BASE_URL %>baselib/MyDll.others.js"></script>
</body>
复制代码
只要运行np run dll命令打包一次即可,若配置有更改,则需重新打包以及引入文件。
3. 总结
至此我们完成了webpack速度优化和体积优化策略的学习,当然还有设计其他优化策略,下一章继续。