手动分包
基本原理
手动分包的总体思路是:
- 先单独的打包公共模块
公共模块会被打包成为动态链接库(dll Dynamic Link Library),并生成资源清单
- 根据入口模块进行正常打包
打包时,如果发现模块中使用了资源清单中描述的模块,则不会形成下面的代码结构
js
//源码,入口文件index.js
import $ from "jquery";
import _ from "lodash";
_.isArray($(".red"));
由于资源清单中包含jquery
和lodash
两个模块,因此打包结果的大致格式是:
js
(function (modules) {
//...
})({
// index.js文件的打包结果并没有变化
"./src/index.js": function (module, exports, __webpack_require__) {
var $ = __webpack_require__("./node_modules/jquery/index.js");
var _ = __webpack_require__("./node_modules/lodash/index.js");
_.isArray($(".red"));
},
// 由于资源清单中存在,jquery的代码并不会出现在这里
"./node_modules/jquery/index.js": function (
module,
exports,
__webpack_require__
) {
module.exports = jquery;
},
// 由于资源清单中存在,lodash的代码并不会出现在这里
"./node_modules/lodash/index.js": function (
module,
exports,
__webpack_require__
) {
module.exports = lodash;
},
});
打包公共模块
打包公共模块是一个独立的打包过程
- 单独打包公共模块,暴露变量名
js
// webpack.dll.config.js
module.exports = {
mode: "production",
entry: {
jquery: ["jquery"],
lodash: ["lodash"],
},
output: {
filename: "dll/[name].js",
library: "[name]",
},
};
- 利用
DllPlugin
生成资源清单
js
// webpack.dll.config.js
module.exports = {
plugins: [
new webpack.DllPlugin({
path: path.resolve(__dirname, "dll", "[name].manifest.json"), //资源清单的保存位置
name: "[name]", //资源清单中,暴露的变量名
}),
],
};
运行后,即可完成公共模块打包
使用公共模块
- 在页面中手动引入公共模块
html
<script src="./dll/jquery.js"></script>
<script src="./dll/lodash.js"></script>
- 重新设置
clean-webpack-plugin
如果使用了插件clean-webpack-plugin
,为了避免它把公共模块清除,需要做出以下配置
js
new CleanWebpackPlugin({
// 要清除的文件或目录
// 排除掉dll目录本身和它里面的文件
cleanOnceBeforeBuildPatterns: ["**/*", "!dll", "!dll/*"],
});
目录和文件的匹配规则使用的是globbing patterns
- 使用
DllReferencePlugin
控制打包结果
js
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: require("./dll/jquery.manifest.json"),
}),
new webpack.DllReferencePlugin({
manifest: require("./dll/lodash.manifest.json"),
}),
],
};
总结
手动打包的过程:
- 开启
output.library
暴露公共模块 - 用
DllPlugin
创建资源清单 - 用
DllReferencePlugin
使用资源清单
手动打包的注意事项:
- 资源清单不参与运行,可以不放到打包目录中
- 记得手动引入公共 JS,以及避免被删除
- 不要对小型的公共 JS 库使用
优点:
- 极大提升自身模块的打包速度
- 极大的缩小了自身文件体积
- 有利于浏览器缓存第三方库的公共代码
缺点:
- 使用非常繁琐
- 如果第三方库中包含重复代码,则效果不太理想
最佳实践
手动打包使用场景:
当多个入口 chunk 有相同的依赖,就可以把依赖提取出来,使用分包。
index.js --> jquery lodash
a.js ---> jquery lodash
- 新建 webpack.dll.config.js 文件,配置打包 dll 的 webpack 文件。
- 使用内置的
webpack.DllPlugin
来生成对应的 dll 资源清单文件。 - 如果使用了
clean-webpack-plugin
插件,需要配置 dll 文件不被删除。 - 给需要打包的 webpack.config.js 文件中配置
DllReferencePlugin
插件,设置打包时的对照规则。 - 在页面中引入公共模块。
json
{
"name": "test",
"version": "1.0.0",
"description": "",
"scripts": {
"dev": "webpack",
"dll": "webpack --config webpack.dll.config.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"html-webpack-plugin": "^3.2.0",
"jquery": "^3.4.1",
"lodash": "^4.17.15",
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11"
}
}
js
const webpack = require("webpack");
const path = require("path");
module.exports = {
mode: "production",
entry: {
jquery: ["jquery"],
lodash: ["lodash"],
},
output: {
filename: "dll/[name].js",
library: "[name]", //将name的名字暴露出去
// libraryTarget: "var", //指定暴露的标准,默认是var
},
//webpack内置的DllPlugin,用来生成资源清单,是一个json对象
plugins: [
new webpack.DllPlugin({
//资源清单保存的位置,可以不在dist文件下,因为只是在构建的时候才需要资源清单
path: path.resolve(__dirname, "dll", "[name].manifest.json"),
name: "[name]", //生成的资源清单的名称
}),
],
};
js
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");
module.exports = {
mode: "development",
devtool: "source-map",
entry: {
main: "./src/index.js",
a: "./src/a.js",
},
output: {
filename: "[name].[hash:5].js",
},
//
plugins: [
//保证打包的时候dll文件不被清除
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ["**/*", "!dll", "!dll/*"],
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
// 配置dll资源清单比对规则
new webpack.DllReferencePlugin({
manifest: require("./dll/jquery.manifest.json"),
}),
new webpack.DllReferencePlugin({
manifest: require("./dll/lodash.manifest.json"),
}),
],
};
js
import _ from "lodash";
import $ from "jquery";
console.log("我是index");
const result = _.isArray($(".red"));
console.log(result);
js
import $ from "jquery";
import _ from "lodash";
const result = _.isArray($(".red"));
console.log(result);
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./dll/jquery.js"></script>
<script src="./dll/lodash.js"></script>
</head>
<body>
<div class="red">123</div>
<div>456</div>
</body>
</html>
最终生成的文件目录
sh
#根目录下的dll
dll
---jquery.manifest.json
---lodash.manifest.json
sh
dist
---dll
---jquery.js
---lodash.js
---main.as212.js
---a.23as65.js
---index.html
构建流程梳理
先利用
DllPlugin
生成对应的资源清单,将公共模块先打包出来。配置打包时,webpack 对照的清单规则,当配置了
DllReferencePlugin
的规则,webpack 在构建的时候就会先对照资源清单,如果发现分包了,就不会将公共模块再打包进最终的 bundle。设置
clean-webpack-plugin
的清除规则,保证已经打包好的 dll 文件夹下的文件不被清除。最终在模板 html 中引用公共模块。