DLL
动态链接库(Dynamic Link Library 或者 Dynamic-link Library),将可以共享,并且不经常改变的代码,抽取成一个共享的库,第二次打包时动态链接 DLL 文件,不重新打包,缩短打包时间。
使用场景
在使用 webpack 开发过程中,对于大量第三方包(如vue、vue-router、axios、elementUI等),并不是经常发生变化。每次编译时都重新构建这些资源,浪费了大量的时间。借助 DLL 思路,webpack 中引入了 DllPlugin 和 DllReferencePlugin ,允许拆分指定的第三方包、并创建单独的包,生成 manifest.json 二次构建跳过这部分编译,并教 Webpack 将它们引用到该包。以此提高整体构建速度。
第一步:指定需要拆分的包,形成 DLL 库
第二步:告知webpack,命中 DLL 库文件
配置
配置需要拆分的包dll.config.js(以开发环境development为例,production环境请自行修改对应配置):
'use strict';
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
mode: 'development', // 环境配置,开发环境用development,打包时使用production
entry: { //配置拆分的包,可配置多入口
vue: ['vue', 'axios'],
antd: ['ant-design-vue', '@ant-design/icons-vue'],
},
output: {
path: path.resolve(__dirname, 'dll'),
filename: '[name].js',
library: '[name]_[hash]'
},
plugins: [
new CleanWebpackPlugin({ cleanAfterEveryBuildPatterns: ['dll'] }), //清空之前的dll文件
new webpack.DllPlugin({
name: '[name]_[hash]', // 需要与output.library保持一致
path: path.resolve(__dirname, 'dll', '[name]-manifest.json'),
format: true, // 使生成的manifest.json文件格式化
context: __dirname //执行上下文
})
]
};
在package.json加命令"dll": "webpack --config ./dll.config.js",执行npm run dll生成DLL文件
使用DllReferencePlugin链接DLL文件。在webpack.config.js文件中配置plugins
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const HtmlWebpackTagsPlugin = require('html-webpack-tags-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const dllConfig = require('./dll.config.js');
module.exports = {
...
plugins:[
...
].concat(useDll())
}
// 对DLL文件做链接处理
function useDll() {
if (!devMode) { // 做好环境区分
return [];
}
const hasDll = fs.existsSync(path.resolve('./dll'));
if (!hasDll) {
console.log('如果构建缓慢请使用dll缓存,请使用npm run dll');
return [];
}
const dllPlugins = [
...Object.keys(dllConfig.entry).map(name => {
return new webpack.DllReferencePlugin({
context: __dirname,
manifest: path.resolve(__dirname, 'dll', name + '-manifest.json') //与dll.config中webpack.DllPlugin path对应
});
}),
// 将构建好的dll文件copy到dist/dll中,有些框架项目会将pulick目录自动拷贝到dist下,而你又正好把dll文件放在pulick目录下,这种情况可忽略这一步
new CopyWebpackPlugin({
patterns: [{ from: 'dll', to: 'dll' }]
}),
// 生成文件链接自动插入到index.html中,不推荐手动添加,很容易出错
new HtmlWebpackTagsPlugin({
tags: Object.keys(dllConfig.entry).map(name => `dll/${name}.js`),
append: false //插入到<head></head>前面,防止加载顺序出错
})
];
return dllPlugins;
}
注意点: 如果依赖更新,需要重新生成dll文件
通常情况下,copy-webpack-plugin、html-webpack-tags-plugin这两个插件可用add-asset-html-webpack-plugin代替,但是由于公司内网原因导致这个插件无法下载,所以找了这个平替方案
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
...
new AddAssetHtmlPlugin({
// dll文件位置
filepath: path.resolve(__dirname, dll ,'./*.js')
})
...
其他更优方案
可以看到,这个手动配置DLL是十分繁琐复杂的,而且容易出错。那么重点来了,有没有轮子可以复用呢?当然有,以下介绍几种比较靠谱、好用的轮子。
1、如果你的项目是基于vueCli3搭建,可借助插件vue-cli-plugin-dll快速配置
2、如果你的项目或者框架是基于webpack<5,可借助插件autodll-webpack-plugin,当依赖更新时会自动生成新的dll文件
3、如果你的项目或者框架基于webpack5,那dll已经不是那么推荐了,反而hard-source-webpack-plugin更为适用,且效率更高。Webpack5 中已对该部分进行了官方实现cache,只需简单配置cache: { type: 'filesystem' },实现秒级启动(当然第一次运行时间还是一样的)