webpack dll 提升构建速度
Posted 奋飛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack dll 提升构建速度相关的知识,希望对你有一定的参考价值。
DLL,动态链接库(Dynamic Link Library 或者 Dynamic-link Library),由微软公司提出。目的是为了节约应用程序所需的磁盘和内存空间。
在一个传统的非共享库中,如果两个程序调用同一个子程序,就会出现两份那段代码。让多个应用共享的代码切分到一个DLL中,在硬盘上存为一个文件,在内存中使用一个实例(instance)。
DllPlugin
和 DllReferencePlugin
用某种方法实现了拆分 bundles,同时还大幅度提升了构建的速度。
- 把公共代码打包为 DLL 文件存到硬盘里;
- 第二次打包时动态链接 DLL 文件,不重新打包;
- 打包时间缩短。
使用场景
在使用 webpack 开发过程中,对于大量第三方包(如vue、vue-router、axios等),并不是经常发生变化。每次编译时都重新构建这些资源,浪费了大量的时间。借助 DLL 思路,webpack 中引入了 DllPlugin
和 DllReferencePlugin
,允许拆分指定的第三方包、并创建单独的包,生成 manifest.json
二次构建跳过这部分编译,并教 Webpack 将它们引用到该包。以此提高整体构建速度。
第一步:指定需要拆分的包,形成 DLL 库 – DllPlugin
第二步:告知webpack,命中 DLL 库文件 – DllReferencePlugin
Without DllPlugin | With DllPlugin | |
---|---|---|
Build Time | 16461ms - 17310ms | 2991ms - 3505ms |
DevServer Rebuild | 2924ms - 2997ms | 316ms - 369ms |
DllPlugin
此插件用于在单独的 webpack 配置中创建一个 dll-only-bundle。 此插件会生成一个名为 manifest.json
的文件,这个文件是用于让 DllReferencePlugin
能够映射到相应的依赖上。生成 manifest.json(实则就是一张映射表)。
entry:
vendor: ['axios', 'vue', 'vue-router', 'vuex']
,
output:
path: './public/dll',
filename: '[name].js',
// vendor.dll.js中暴露出全局变量名
// 保持与webpack.DllPlugin中name一致
library: '[name]_[hash]',
publicPath: '/dll/'
,
plugins: [
// manifest.json描述动态链接库包含了哪些内容
new webpack.DllPlugin(
path: path.resolve('./public/dll', '[name]-manifest.json'),
// 保持与output.library中名称一致
name: '[name]_[hash]',
context: process.cwd()
)
]
生成的 manifest.json
文件中,包含了从 require 和 import 中 请求到模块 id 的映射。
"./node_modules/.pnpm/axios@0.18.1/node_modules/axios/index.js":
"id": "./node_modules/.pnpm/axios@0.18.1/node_modules/axios/index.js",
"buildMeta":
"providedExports": true
DllReferencePlugin
此插件配置在 webpack 的主配置文件中,此插件会把 dll-only-bundles 引用到需要的预编译的依赖中。
通过引用 dll 的 manifest 文件来把依赖的名称映射到模块的 id 上,之后再在需要的时候通过内置的 __webpack_require__
函数来 require
对应的模块
plugins: [
new webpack.DllReferencePlugin(
context: process.cwd(),
manifest: path.resolve('./public/dll', 'vendor-manifest.json')
),
new AddAssethtmlPlugin([
filepath: path.resolve('./public/dll', 'vendor.js'),
typeOfAsset: 'js',
publicPath: '/dll/'
,
filepath: path.resolve('./public/dll', 'vendor.css'),
typeOfAsset: 'css',
publicPath: '/dll/'
]),
]
遗留问题
通过上述配置构建速度得了提升,但其配置比较复杂。同时,会存在一些问题:
- 变更了包(新增、删除、版本),需要手动重新构建,生成 DLL
- Dev Server 模式下,资源都被加载到内存中,DLL 方式依然会从文件系统中读取
AutoDllPlugin
AutoDllPlugin 插件完美解决了上述问题,隐藏了大量配置的复杂性。
当第一次构建包时,AutoDllPlugin 会编译 DLL,并将包中的所有指定模块引用到 DLL;下次编译代码时,AutoDllPlugin 将跳过构建并改为从缓存中读取。每次更改插件配置、安装或删除节点模块时,AutoDllPlugin 都会重建 DLL。当使用 Webpack 的 Dev Server 时,bundle 被加载到内存中以防止从文件系统中进行不必要的读取。
plugins: [
new HtmlWebpackPlugin(
inject: true, // 将 main bundle 注入到 index.html
template: './public/index.html',
),
new AutoDllPlugin(
inject: true, // 将 DLL bundle 注入到 index.html
filename: '[name]_[hash].js',
path: '/dll',
entry:
vendor: ['axios', 'vue', 'vue-router', 'vuex']
)
]
AutoDllPlugin 有被 vue-cli 使用,所以可放心使用。
但在 vue-cli 引入 webpack4 之后,移除了该包,“因为 Webpack 4 的打包性能足够好的,dll 没有在 Vue ClI 里继续维护的必要了。”
dll
option will be removed. Webpack 4 should provide good enough perf and the cost of maintaining DLL mode inside Vue CLI is no longer justified. – https://github.com/vuejs/vue-cli/issues/1205
HardSourceWebpackPlugin
AutoDllPlugin 其 github 仓库中,给出了重要提示。
HardSourceWebpackPlugin 为模块提供中间缓存步骤。
Webpack5 中已对该部分进行了官方实现。
总结
按照上面的描述,我们应该摒弃 webpack dll 吗?
不然,webpack dll 除了提升构建速度,它还允许在不同项目之间共享代码(初衷)。
以上是关于webpack dll 提升构建速度的主要内容,如果未能解决你的问题,请参考以下文章
webpack 提升90%的构建速度 HardSourceWebpackPlugin
webpack优化篇(四十六):充分利用缓存提升二次构建速度