使用 DllPlugin 插件先提前打包一些不经常变化的第三方库,然后在后面项目打包的时候直接引用它们,而不需要重新打包这些库,这样可以有效的提升项目打包速度。
基础配置#
首先,需要新建一个 Webpack 配置文件webpack.dll.config.js,配置文件的代码如下
const path = require("path");
const webpack = require("webpack");
module.exports = {
mode: "production",
entry: {
vendors: ["react", "react-dom"],
},
output: {
path: path.resolve(__dirname, "dll"),
filename: "[name].dll.js",
library: "[name]", // 设置库的名称
},
plugins: [
// 使用 DllPlugin 插件
new webpack.DllPlugin({
name: "[name]",
path: path.resolve(__dirname, "dll/[name].manifest.json"), // 打包后存储路径
}),
],
};这里把react和react-dom这两个库先提前打包,输出一个vendors的文件。在新的配置文件中需要引入webpack自带``DllPlugin`插件,这样才能按照配置生成新的所需要的打包文件。
在package.json新增一个打包命令
"scripts": {
"build:dll": "webpack --config webpack.dll.config.js"
}然后进行编译打包
yarn build:dll发现在根目录下面新增了dll文件夹,里面是刚才打包生成的两个文件
vendors.dll.js打包后的文件vendors.manifest.json打包后的文件映射清单
现在已经提前打包好了两个第三方库,然后需要修改原来 Webpack 的配置文件webpack.config.js
// ...
const webpack = require("webpack");
const AddAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin");
module.exports = {
// ...
plugins: [
// ...
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, "dll/vendors.dll.js"),
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "dll/vendors.manifest.json"),
}),
],
};这里还是使用了DllReferencePlugin插件,但是配置不一样,这里配置manifest选项引入之前打包好的文件的映射清单,然后再借助一个第三方库add-asset-html-webpack-plugin把打包好的文件引入到现在的 HTML 文件中。
修改好原来的配置文件后,重新进行打包编译。
yarn build文件打包成功。我们可以通过注释掉DllReferencePlugin插件的代码,进行编译打包,多打包几次。然后取消注释,也进行编译打包,也多打包几次。然后比较这两种配置之间的打包时间,就会发现使用DllReferencePlugin插件后编译打包的时间明显更少。因为使用DllReferencePlugin插件后就不需要再重新去打包react和react-dom这两个库了,而是直接引用原来已经打包好的文件。
现在启动开发模式测试一下。
yarn dev发现编译也是成功的。
多个入口配置#
目前项目只是提前打包了两个第三方库,打包后生成的文件也只有两个。但是随着项目越来越大,使用的第三方库会越来越多,到时候需要提前打包的库也会越来越多。这时,也不可能把所有的库都打包在一起,可以把它们分开打包,这时候需要使用多个入口来进行编译打包。
比如我们还引用了lodash库,修改webpack.dll.config.js配置文件,增加一个新的入口
module.exports = {
entry: {
vendors: ["lodash"],
react: ["react", "react-dom"],
},
// ...
};然后重新进行编译打包,发现在根目录下面的dll文件夹下,里面变成了四个文件,比原来的数目多了两个,这是因为增加了一个入口,所以打包后多出了两个文件。
这样就需要再次修改webpack.config.js配置文件,把上面打包多出来的两个文件也要引入进来。
module.exports = {
// ...
plugins: [
// ...
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, "dll/vendors.dll.js"),
}),
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, "dll/react.dll.js"),
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "dll/vendors.manifest.json"),
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "dll/react.manifest.json"),
}),
],
};重新进行编译打包,打包成功。使用开发者模式测试代码,编译也是成功的。
自动引入#
上面使用dllPlugin配置了两个入口,打包出来四个文件。如果项目很大的话,可能需要提前打包很多的库。入口也会变的更多,打包出来的文件也会更多,那么在原来的webpack.config.js文件也需要引入更多的文件。而且我们不可能每次打包后都需要手动引入进来,这样会非常麻烦,这时需要编写代码自动引入提前打包好的库。
我们可以使用 Node.js 的 fs 模块读取dll文件夹的所有文件信息,然后遍历这样文件,通过正则表达式筛选出文件类型,再通过插件引入相应的文件,这样就不怕引入的文件很多,因为可以自动引入文件了。
修改webpack.config.js配置文件
// ...
const fs = require("fs");
// 先把其他的插件提取出来
const plugins = [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "index.html"),
filename: "index.html",
}),
new webpack.HotModuleReplacementPlugin(),
];
// 读取打包后的所有文件名
const files = fs.readdirSync(path.resolve(__dirname, "dll"));
// 遍历文件名,通过正则匹配使用插件引入对应的文件
files.forEach((file) => {
if (/.*\.dll.js/.test(file)) {
plugins.push(
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, "dll", file),
})
);
}
if (/.*\.manifest.json/.test(file)) {
plugins.push(
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "dll", "vendors.manifest.json"),
})
);
}
});
module.exports = {
// ...
plugins,
};修改配置的步骤如下
- 通用的插件先提取出来,存储在
plugins数组中。 - 通过
fs.readdirSync读取dll文件夹中所有的文件名信息,存储到files数组中。 - 遍历文件名数组
files,通过正则表达式匹配文件名,再使用插件引入匹配的文件,再把插件放入到plugins数组中。 - 最后把
plugins数组赋值给配置文件的plugins字段中。
重新进行编译打包,打包成功。使用开发者模式测试代码,编译也是成功的。说明自动引入的方法是有效的,以后再也不用担心提前打包的文件多的问题。