介绍
在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,vue 我们希望能和自己的代码分离开,Webpack 社区有两种方案
CommonsChunkPlugin
DLLPlugin
对于 CommonsChunkPlugin,webpack 每次打包实际还是需要去处理这些第三方库,只是打包完之后,能把第三方库和我们自己的代码分开。而 DLLPlugin 则是能把第三方代码完全分离开,即每次只打包项目自身的代码。Dll这个概念是借鉴了Windows系统的dll,一个dll包,就是一个纯纯的依赖库,它本身不能运行,是用来给你的app引用的
使用
添加配置文件
要使用 DLLPlugin,需要额外新建一个配置文件webpack.dll.js,该配置文件用来打包生成第三方库。
webpack.dll.js
const webpack = require('webpack')
const path = require('path')
module.exports = {
mode: 'production',
entry: {
vendor: ['lodash'],
react: ['react']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, './dll'),
library: '[name]',
// libraryTarget: 'umd' // 将入口文件的返回值以什么类型的方式导出,umd比较全,包括amd、cmd、window
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.join(__dirname, './dll/[name].manifest.json')
})
]
}
然后运行 命令行运行"webpack --config webpack-dll.js"
生成打包后的文件
接下来就是,这么在业务代码里使用打包好的第三方模块的事情了。
修改配置文件webpack-common.js
关键代码如下:
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
....
plugins: [
new AddAssetHtmlWebpackPlugin({//将打包好的dll文件挂载到html中
filepath: path.resolve(__dirname, './dll/react.dll.js')
}),
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, './dll/vendor.dll.js')
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, './dll/vendor-manifest.json')
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, './dll/react-manifest.json')
})
],
浏览器控制台,可以看到第三方模块,已经作为全局变量,引入到了入口文件中。
但是每次在webpack.dll.js新加第三方模块,都要在webpack-common.js里添加DllReferencePlugin等,比较麻烦,我们可以用node写一个文件循环,自己读取文件数量,自动修改plugin
关键代码如下:
const fs = require('fs')
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
const plugins = [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin(),
new BundleAnalyzerPlugin(),
new webpack.ProvidePlugin({
_: 'lodash'
}),
]
files.forEach(file => {
if (/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({//将打包好的dll文件挂载到html中
filepath: path.resolve(__dirname, '../dll', file)
}))
}
if (/.*\.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({//分析第三方模块是否已经在dll文件里,如果里面有就不用再node_modules在分析打包了
manifest: path.resolve(__dirname, '../dll', file)
}))
}
})
总结整体流程
通过dllPlugin生成manifets.json和vendor.js,vendor.js会自执行返回一个加载函数vendor(名字可配置),通过闭包将模块存储在内存中,注意vendor是一个全局变量。
webpack通过DllReferencePlugin在打包的时候分析业务代码中使用了哪些第三方模块,哪些模块是不需要打包进业务代码中,而是去vendor.js中获取。
vendor中获取的模块是通过调用全局函数vendor(id)来进行引入。
补充
CommonsChunkPlugin 插件每次打包的时候还是会去处理一些第三方依赖库,只是它能把第三方库文件和我们的代码分开掉,生成一个独立的js文件。但是它还是不能提高打包的速度。
DLLPlugin 它能把第三方库代码分离开,并且每次文件更改的时候,它只会打包该项目自身的代码。所以打包速度会更快。
DLLPlugin 这个插件是在一个额外独立的webpack设置中创建一个只有dll的bundle,也就是说我们在项目根目录下除了有webpack.config.js,还会新建一个webpack.dll.config.js文件。webpack.dll.config.js作用是把所有的第三方库依赖打包到一个bundle的dll文件里面,还会生成一个名为 manifest.json文件。
该manifest.json的作用是用来让 DllReferencePlugin 映射到相关的依赖上去的。
DllReferencePlugin 这个插件是在webpack.config.js中使用的,该插件的作用是把刚刚在webpack.dll.config.js中打包生成的dll文件引用到需要的预编译的依赖上来。什么意思呢?就是说在webpack.dll.config.js中打包后比如会生成 vendor.dll.js文件和vendor-manifest.json文件,vendor.dll.js文件包含所有的第三方库文件,vendor-manifest.json文件会包含所有库代码的一个索引,当在使用webpack.config.js文件打包DllReferencePlugin插件的时候,会使用该DllReferencePlugin插件读取vendor-manifest.json文件,看看是否有该第三方库。vendor-manifest.json文件就是有一个第三方库的一个映射而已。
所以说 第一次使用 webpack.dll.config.js 文件会对第三方库打包,打包完成后就不会再打包它了,然后每次运行 webpack.config.js文件的时候,都会打包项目中本身的文件代码,当需要使用第三方依赖的时候,会使用 DllReferencePlugin插件去读取第三方依赖库。所以说它的打包速度会得到一个很大的提升。