【webpack】webpack优化
量化分析
speed-measure-webpack-plugin
speed-measure-webpack-plugin
插件可以测量各个插件和 loader 所花费的时间,用这个插件可以很好的判断优化效果。
webpack 5
中使用会打印大量 error 信息,并且会导致 cache 不生效。
无法与 HardSourceWebpackPlugin 插件一起使用。
- 安装
npm i speed-measure-webpack-plugin -D
- 使用
直接用 SpeedMeasurePlugin 的实例包裹 webpack 配置即可。
//webpack.config.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const config = {
//...webpack配置
};
module.exports = smp.wrap(config);
使用之后,构建时会多打印一些信息,示例如下:
SMP ⏱
General output time took 27.43 secs
SMP ⏱ Plugins
TerserPlugin took 11.92 secs
HtmlWebpackPlugin took 0.702 secs
CopyPlugin took 0.097 secs
SMP ⏱ Loaders
thread-loader, and
babel-loader took 12.78 secs
module count = 119
mini-css-extract-plugin, and
css-loader, and
postcss-loader, and
less-loader took 0.059 secs
module count = 32
webpack-bundle-analyzer
webpack-bundle-analyzer
插件可以生成依赖分析报告,可以直观地分析打包出来的文件有那些及它们的大小。
- 安装
npm install webpack-bundle-analyzer -D
- 配置
//webpack.config.prod.js
const BundleAnalyzerPlugin =
require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.config.base");
module.exports = merge(baseWebpackConfig, {
//....
plugins: [
//...
new BundleAnalyzerPlugin(),
],
});
缩减 loader 的校验范围
我们可以通过 exclude、include 配置来确保转译尽可能少的文件。顾名思义,exclude 指定要排除的文件,include 指定要包含的文件。
exclude 的优先级高于 include,在 include 和 exclude 中使用绝对路径数组,尽量避免 exclude,更倾向于使用 include。
//webpack.config.js
const path = require("path");
module.exports = {
//...
module: {
rules: [
{
test: /\.js[x]?$/,
use: ["babel-loader"],
include: [path.resolve(__dirname, "src")],
},
],
},
};
缓存 loader
在一些性能开销较大的 loader 之前添加 cache-loader,将结果缓存中磁盘中。默认保存在 node_modueles/.cache/cache-loader 目录下。
保存和读取这些缓存文件会有一些时间开销,所以请只对性能开销较大的 loader 使用 cache-loader
。
- 安装
npm install cache-loader -D
- 配置
在需要缓存的 loader 之前添加 cache-loader
。
module.exports = {
//...
module: {
//我的项目中,babel-loader耗时比较长,所以我给它配置了`cache-loader`
rules: [
{
test: /\.jsx?$/,
use: ["cache-loader", "babel-loader"],
},
],
},
};
缓存模块和 chunk
webpack 5
提供了 cache 选项以开启缓存,默认开发环境时被设置为 type:'memory'
,生产环境中被禁用。
在生产环境下配置 type 为 filesystem 可以实现持久化缓存,webpack 会在第一次构建时生成缓存文件,在后续构建时用以改善构建速度。
默认缓存位置为:node_modules/.cache/webpack
。
其他配置见webpack cache 官方文档。
exports.module = {
cache: {
type: "filesystem",
},
};
在更低版本中 HardSourceWebpackPlugin 插件也可达到同样的效果,见带你深度解锁 Webpack 系列(优化篇)关于 HardSourceWebpackPlugin 的内容。
多进程打包
把 thread-loader 放置在其它 loader 之前,那么放置在这个 loader 之后的 loader 就会在一个单独的 worker 池中运行。
在 worker 池(worker pool)中运行的 loader 是受到限制的。例如:
- 这些 loader 不能产生新的文件。
- 这些 loader 不能使用定制的 loader API(也就是说,通过插件)。
- 这些 loader 无法获取 webpack 的选项设置。
- 安装
npm install thread-loader -D
- 配置
module.exports = {
module: {
//我的项目中,babel-loader耗时比较长,所以我给它配置 thread-loader
rules: [
{
test: /\.jsx?$/,
use: ["thread-loader", "cache-loader", "babel-loader"],
},
],
},
};
标志无需转化和解析的模块
如果一些第三方模块没有 AMD/CommonJS 规范版本,可以使用 noParse 来标识这个模块,这样 Webpack 会引入这些模块,但是不进行转化和解析,从而提升 Webpack 的构建性能 ,例如:jquery 、lodash。
- 配置
//webpack.config.js
module.exports = {
//...
module: {
noParse: /jquery|lodash/,
},
};
引入线上资源而不是打入包中
对于一些第三方库(jquery),可以通过加载 jquery 的 cdn 链接来引入而不是全部下载到本地,这样就可以减少打包出来的 js 体积。
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
我们希望在使用时,仍然可以通过 import 的方式去引用(如 import $ from 'jquery'),并且希望 webpack 不会对其进行打包,此时就可以配置 externals。
//webpack.config.js
module.exports = {
//...
externals: {
//jquery通过script引入之后,全局中即有了 jQuery 变量
jquery: "jQuery",
},
};
单独打包不常变化的依赖
如果将所有 js 文件都打包,会导致最终生产的 js 文件很大。
对于不常变化的依赖,可以将其单独编译打包,当这些依赖没有变化时,就不需要重新编译。
感觉这种方法不如直接用上一个方法将依赖用 CDN 加载。
见 带你深度解锁 Webpack 系列(优化篇) 中的 DllPlugin 部分。
抽离公共代码
抽离公共代码是对于多入口应用来说的,如果多个页面引入了一些公共模块,那么可以把这些公共的模块抽离出来,单独打包。
公共代码只需要下载一次就缓存起来了,避免了重复下载。
//webpack.config.js
module.exports = {
optimization: {
splitChunks: {
//分割代码块
cacheGroups: {
vendor: {
//第三方依赖
priority: 1, //设置优先级,首先抽离第三方模块
name: "vendor",
test: /node_modules/,
chunks: "initial",
minSize: 0,
minChunks: 1, //最少引入了1次
},
//缓存组
common: {
//公共模块
chunks: "initial",
name: "common",
minSize: 100, //大小超过100个字节
minChunks: 3, //最少引入了3次
},
},
},
},
};