Webpack DllPlugin 详解:原理、配置与性能优化实践
本文深入解析 Webpack 中 DllPlugin 的工作原理与配置方法,通过分离第三方库与业务代码实现构建加速。文章涵盖基本用法、DllReferencePlugin 的配置细节,并结合实际案例探讨何时引入动态链接库能显著提升构建效率,同时利用 webpack-bundle-analyzer 进行性能评估与避坑指南。
前言
(时光飞逝,转眼又偷懒了一个多月)
DLL 原理与引入必要性
什么是DLL
DLL(Dynamic Link Library)即动态链接库文件。在 Windows 系统中,许多应用程序并非单一的可执行文件,而是被分割为多个相对独立的动态链接库,存放于系统目录中。当执行特定程序时,系统会调用相应的 DLL 文件以提供所需功能。
举个通俗的例子:许多产品在生产过程中需要用到螺丝,但工厂无需每次生产新产品时都重新制造螺丝,因为螺丝可以单独生产并通用。在这里,螺丝的作用就相当于 DLL,即被多个模块共享的基础组件。
为什么要使用Dll
通常代码可分为业务代码和第三方库。若不进行特殊处理,每次构建都需重新编译所有代码,耗时巨大。由于第三方库代码在版本未升级时通常保持不变,此时可利用 DLL 技术:将复用性高的第三方模块打包至动态链接库中。只要这些库未升级,动态库无需重新打包,每次构建仅需重新打包业务代码,从而节省时间。
沿用上述例子:将每次构建视为产品生产流程,我们将生产螺丝的过程预先提取出来。此后,无论调整产品功能或设计(对应业务代码变更),都无需重复生产螺丝(第三方模块无需重复打包);仅当产品需使用新型号螺丝(第三方模块升级)时,才需重新生产新螺丝,随后即可专注于产品本身的调整。
基本用法
Webpack DllPlugin 基本配置
使用 DLL 时,构建过程需分为 DLL 构建过程和主构建过程,因此需要两个构建配置文件,例如分别命名为 webpack.config.js 和 webpack.dll.config.js。
1. 使用DLLPlugin打包需要分离到动态库的模块
DllPlugin是webpack内置的插件,无需额外安装,直接配置webpack.dll.config.js文件即可:
module.exports = {=
entry: {
// 第三方库
react: ['react', 'react-dom', 'react-redux']
},
output: {
// 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
filename: '[name].dll.js',
path: resolve('dist/dll'),
// library必须和后面dllplugin中的name一致 后面会说明
library: '[name]_dll_[hash]'
},
plugins: [
// 接入 DllPlugin
new webpack.DllPlugin({
// 动态链接库的全局变量名称,需要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
name: '[name]_dll_[hash]',
// 描述动态链接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist/dll', '[name].manifest.json')
}),
]
}
我们先来看看,这一步到底做了什么。执行:webpack --config webpack.dll.config,然后到指定的输出文件夹查看输出:
react.dll文件里是使用数组保存的模块,索引值就作为id;react.manifest.json文件里,是用来描述对应的dll文件里保存的模块
里暴露出刚刚构建的所有模块,如下:
{
"name":"react_dll_553e24e2c44987d2578f",
"content":{
"./node_modules/webpack/node_modules/process/browser.js":{"id":0,"meta":{}},"./node_modules/react/node_modules/fbjs/lib/invariant.js":{"id":1,"meta":{}},"./node_modules/react/lib/Object.assign.js":{"id":2,"meta":{}},"./node_modules/react/node_modules/fbjs/lib/warning.js":{"id":3,"meta":{}}
//省略相似代码
}
}
主构建流程中的动态库引用
2. 在主构建配置文件使用动态库文件
在webpack.config中使用dll要用到DllReferencePlugin,这个插件通过引用 dll 的 manifest 文件来把依赖的名称映射到模块的 id 上,之后再在需要的时候通过内置的 webpack_require 函数来 require 他们.
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./dist/dll/react.manifest.json')
}),
第一步产出的manifest文件就用在这里,给主构建流程作为查找dll的依据:DllReferencePlugin去 manifest.json 文件读取 name 字段的值,把值的内容作为在从全局变量中获取动态链接库中内容时的全局变量名,因此:在 webpack_dll.config.js 文件中,DllPlugin 中的 name 参数必须和 output.library 中保持一致。
3. 在入口文件引入dll文件。
生成的dll暴露出的是全局函数,因此还需要在入口文件里面引入对应的dll文件。
<body>
<div id="app"></div>
<!--引用dll文件-->
<script src="../../dist/dll/react.dll.js" ></script>
</body>
DLL 分离代码的作用与优势
作用
首先从前面的介绍,至少可以看出dll的两个作用
分离代码,业务代码和第三方模块可以被打包到不同的文件里,这个有几个好处:
- 避免打包出单个文件的大小太大,不利于调试
- 将单个大文件拆成多个小文件之后,一定情况下有利于加载(不超出浏览器一次性请求的文件数情况下,并行下载肯定比串行快)
提升构建速度。第三方库没有变更时,由于我们只构建业务相关代码,相比全部重新构建自然要快的多。
DLL 使用的注意事项与性能权衡
注意事项
从前面可以看到dll带来的优点,但并不意味着我们就应该把除业务代码外的所有代码全部都丢到dll中,举一个例子:
1.对于lodash这种第三方库,正确的用法是只去import所需的函数(用什么引什么),例如:
// 正确用法
import isPlainObject from 'lodash/isPlainObject'
//错误用法
import { isPlainObject } from 'lodash'
这两种写法的差别在于,打包时webpack会根据引用去打包依赖的内容,所以第一种写法,webpack只会打包lodash的isPlainObject库,第二种写法却会打包整个lodash。现在假设在项目中只是用到不同模块对lodash里的某几个函数并且没有对于某个函数重复使用非常多次,那么这时候把lodash添加到dll中,带来的收益就并不明显,反而导致2个问题:
- 由于打包了整个
lodash,而导致打包后的文件总大小(注意是总大小)比原先还要大 - 在dll打包太多内容也需要耗费时间,虽然我们一般只在第三方模块更新之后才进行重新预编译(就是dll打包的过程),但是如果这个时间太长的话体验也不好、
实际项目中的构建收益与反思
实践与反思
放一张自己在一个比较大的项目中单纯使用dll之后的收益,提取的内容是 react相关的第三方库,和fish组件,构建时间从120s降低到80s左右(当然这个时间还是有点恐怖),构建前appjs的大小是680kb,拆分业务代码和第三方代码分别是400kb和380kb(这就是拆分后大小大于拆分前大小的例子),从这一点来看,对于常见第三方库是否要放进dll可能比较明确(比如react系列打包一般肯定不亏),但是还有一些就要结合具体的项目内容来进行判断和取舍。(强烈推荐使用webpack-bundle-analyzer插件进行性能分析)



总结
本文介绍了Dllplugin的思想,基本用法和应用场景(关于使用的部分更详细的内容可以看官方文档),结合个人的一些实践经验,对于常见第三方库是否要放进dll可能比较明确(比如react系列打包一般肯定不亏),但是还有一些就要结合具体的项目内容来判断,例如我上面的实践的例子就说明目前的拆分还不够好。这一块也欢迎大家一起探讨。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
UmiJS 项目构建速度优化与打包体积精简技巧
2026-11-04 22:37:09
原生JS操作DOM与Vue/React虚拟DOM的本质区别
2026-11-04 17:52:27
怎么使用console.group和table优化JS日志可读性
2026-11-03 23:14:34
基于AST抽象语法树的JS代码反混淆实战教程
2026-11-03 21:22:24
JS手机号输入校验的性能优化与用户体验提升
2026-11-03 19:19:19
