webpack打包时会将第三方包和业务代码一起打包,实际上第三方包不经常变化,不需要每次都参与打包。
如果把第三方包打包成一个库,供项目使用,那么打包第三方包的操作只需要在依赖包发生变化时进行一次即可。并且将第三方包提取出来,业务代码的打包速度也会提高。
打包DLL
例如一般react项目都会用到react和react-dom两个包,可以把它们提取成一个库,提供react项目使用,这样打包该项目的时候react和react-dom就不会参与打包了。
webpack 提供了一个插件:DllPlugin,可以把多个包打包成一个库。
// webpack.dll.js 打包dll的配置文件
const path = require('path')
const webpack = require('webpack')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
mode: "production",
entry: {
react: ['react', 'react-dom'], // 将react和react-dom打包成一个库,这里有多少个数组就会生成多少个库文件
jquery: ['jquery']
},
output: {
path: path.resolve(__dirname, 'dll'),
filename: 'dll_[name].js',
library: 'dll_[name]'
},
optimization: {
minimizer: [
new TerserPlugin({
extractComments: false // 不生成库的LICENCE文件
}),
],
},
plugins: [
new webpack.DllPlugin({
name: 'dll_[name]',
path: path.resolve(__dirname, './dll/[name].manifest.json')
})
]
}
生成的库:
manifest.json 用来指示库的位置索引。
比如react的库的内容如下:
使用DLL
webpack提供的另外一个插件:DllReferencePlugin 可以加载已经打包的库。
plugins: [
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
}),
new webpack.DllReferencePlugin({
context: resolveApp('./'), // 指定上下文,和manifest.json对应的库文件的位置,如果在同一个文件夹,写 ./
manifest: resolveApp('./dll/react.manifest.json') // 指定manifest.json的路径
}),
]
这样webpack打包就不会将react一并打包,但是这样打包生成的index.html文件并不会引用库文件,需要另外的插件:AddAssetHtmlPlugin 将库文件添加到index.html的script标签。
plugins: [
new HtmlWebpackPlugin({
title: 'copyWebpackPlugin',
template: './public/index.html'
}),
new webpack.DllReferencePlugin({
context: resolveApp('./'), // 指定上下文,和manifest.json对应的库文件的位置,如果在同一个文件夹,写 ./
manifest: resolveApp('./dll/react.manifest.json') // 指定manifest.json的路径
}),
new AddAssetHtmlPlugin({
outputPath: 'js', // 输出到 js 文件夹
filepath: resolveApp('./dll/dll_react.js') // 库文件路径
})
]
发现生成的index.html,引用的库文件总是放在一个auto文件夹,但这个文件夹事实上并不存在,在这个例子中dll_react.js放在了js文件夹中,可能是 bug。所以把AddAssetHtmlPlugin配置的输出文件夹也改成auto会比较好,否则要去手动更改index.html。