上篇文章,已经说明了进行优化的前期准备,如何查看构建统计信息、速度分析,以及体积分析。这篇文章就写写,如何进行具体的优化。
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 速度优化和体积优化策略的学习,当然还有设计其他优化策略,下一章继续。
评论