使用Webpack DllPlugin

DllPlugin 简易使用指南

  1. 创建webpack.dll.config.js 用于对特定的模块打包成dll
  2. webpack --config webpack.dll.config.js 生成dll以及其描述文件
  3. webpack.common.config.js中使用DllReferencePlugin引入打包好的dll文件。
  4. 打包。此时遇到相应的模块时直接引入而不会重新打包。

创建webpack.dll.config.js

这里以分别打包momentlodash为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// config.js
module.exports = {
entry: {
lodash: ['lodash'],
moment: ['moment'],
}
}
// webpack.dll.config.js
const webpack = require('webpack');
const path = require('path');
const config = require('./config');
module.exports = {
entry: config.entry,
output: {
path: path.resolve(__dirname, '/static/dll'),
filename: '[name].dll.js',
library: '[name]_library'
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, '/static/dll', '[name]-manifest.json'),
name: '[name]_library',
context: __dirname,
})
]
}

解释:

  1. 推荐把入口配置信息写在单独文件中,易于维护。
  2. DllPlugin类接受一个配置对象,该对象有三个属性:context(绝对路径), manifest文件中请求上下文;name,暴露的dll函数名;path:manifest文件存放的位置(绝对路径)。

使用DllReferencePlugin

1
2
3
4
5
6
7
8
9
10
11
12
// webpack.common.config.js
const config = require('./config');

module.exports = {
... // 省略其它配置
plugins: [
...Object.keys(dllConfig.entry).map((name) => new new webpack.DllReferencePlugin({
context: __dirname,
manifest: require(`./static/dll/${name}-manifest.json`),
}))
]
}

DllReferencePlugin 接受一个对象用于初始化

  1. context: manifest的上下文(绝对路径),需和DllPlugin中的context一致
  2. manifest: manifest文件,使用require引入或指定绝对路径

可选参数:

  1. content:模块id的映射,默认为 manifest.content
  2. name: dll文件的名称,默认为 manifest.name
  3. scope: dll 内容前缀
  4. sourceType: dll如何暴露的?amd commonjs2 …

scope: ‘abc’, 则该dll中的xyz文件可以通过require(‘abc/xyz’)来引用
例如在一个dll中打包了lodashaxios两个库,并且指定了{scope: 'lib'},则在需要使用axios的时候使用require('lib/axios')即可。

测试1:把echartswinduireact及其周边分别抽取成dll文件。

抽取的dll文件大小分别为:753KB 1603KB,385KB。

构建方式 平均构建时间 包大小
普通 97s 4.1MB
使用Dll 71s 2.6MB
dll文件 24s 2.7MB

经过对比发现,由于无法使用按需加载,所以整个windui打包的大小差不多为1.6MB,而普通的打包方式windui的大小仅为365KB。

在使用windui链接库后生成的打包,发现vendors模块中仍然含有windui,大小为330KB,仅windui中的node_modules文件夹下的rc-triggerrc-dropdown被重用,因此这里可能重复打包了。

windui中依赖的rc-*部分模块仍然被打包。

方式二 仅对react相关模块和echarts进行打包

抽取的两个dll文件的大小为393KB 769KB

构建方式 平均构建时间 包大小
普通 97s 4.1MB
使用DLL 77s 3.08MB
dll 11s 1.16MB

windui的大小基本不变,而windui依赖的rc-*系列组件基本没被打包。

vendors模块从0.61MB1.67MB

使用html-webpack-include-assets-plugin 把dll注入到index.html

1
2
3
4
5
const HtmlWebpackIncludeAssetsPlugin = require('html-webpack-include-assets-plugin');
const dllIntoHtml = new HtmlWebpackIncludeAssetsPlugin({
assets: ['./static/dll/echarts.dll.js', './static/dll/react.dll.js'], // 需要注入的dll文件路径
append: false, // 是否尾注入?push : unshift
});

因为先构建dll,再进行项目构建,在项目构建过程中会删除整个build目录,所以在构建完后再把dll文件夹拷贝进build/static/

总结

  1. windui进行dll打包后会因为无法按需加载而导致总大小偏高(且可能会产生冗余);而不进行的话,包的总大小基本不变。

  2. 初始时需要加载的chunk从3个变为6个/5个

升级到webpack4.x

升级到webpak4.x后无论是dll还是最终生成块,都有小幅度的下降。与此同时,构建总时间(dll构建时间+项目build时间)略微减小。

关于使用已存在的模块直接作为dll文件引入的可能性

  1. 目前无相关方面的实践。
  2. DllPlugin抽取特定的模块构建dll文件后会生成一个manifest文件。该存储了各个模块的和公共模块的对应关系。
    该文件会对已经打包成dll的模块中的文件进行描述,会给每个文件指定id,并且该json文件中的name属性对应dll的library
  3. 在进行项目构建的时候,如需要打包某个模块,会在manifest文件中查找,如果该模块已经存在于dll中,依据manifest中的信息进行链接即可,不必重新打包。

构建的dll块和使用splitChunk或者直接使用babel打包出来的块不一致。其依赖构建dll时指定的library等,而manifest文件也是和该块一一对应的。所以从理论上,使用其它方式提供dll文件由于构建方式和无法提供manifest文件,在构建过程中并不能被重用。

PS: 本片文章来自于我在团队内部分享的笔记,任何关于webpack-dll-plugin的理解和使用方式请在该插件的Webpack介绍页查看

分享到 评论