一、DLLPlugin的使用
1、背景
对于vue项目而言,不可避免的会使用一些第三方的库,这些库本身并不会运行,我们也不会修改这些库的代码,但是每当我们修改了业务代码之后,这些库也会被重新打包,极大的浪费了时间,这时我们就需要使用工具预先把静态资源提前打包,以后修改源文件再打包时就不会打包这些静态资源文件了。而webpack在打包的时候,对于一些不经常更新的第三方库,比如 d3
,lodash
,我们希望能和自己的代码分离开,也就是单独打包。
2、简介
DLLPlugin
和 DLLReferencePlugin
用某种方法实现了拆分 bundles,同时还大大提升了构建的速度。
DllPlugin
这个插件是在一个额外的独立的 webpack 设置中创建一个只有 dll 的 bundle(dll-only-bundle)。 这个插件会生成一个名 为 manifest.json
的文件,这个文件是用来让 DLLReferencePlugin
映射到相关的依赖上去的。
context
(optional): manifest 文件中请求的上下文(context)(默认值为 webpack 的上下文(context))
name
: 暴露出的 DLL 的函数名 (TemplatePaths: [hash]
& [name]
)
path
: manifest json 文件的绝对路径 (输出文件)
在给定的 path
路径下创建一个名为 manifest.json
的文件。 这个文件包含了从 require
和 import
的request到模 块 id 的映射。 DLLReferencePlugin
也会用到这个文件。
new webpack.DllPlugin({
path: path.resolve(__dirname, '../libs/[name]-mainfest.json'),
name: '[name]_library',
context: __dirname, // 执行的上下文环境,对之后DllReferencePlugin有用
}),
llReferencePlugin
这个插件是在 webpack 主配置文件中设置的, 这个插件把只有 dll 的 bundle(们)(dll-only-bundle(s)) 引用到需要的预编译的依赖。
context
: (绝对路径) manifest (或者是内容属性)中请求的上下文manifest
: 包含content
和name
的对象,或者在编译时(compilation)的一个用于加载的 JSON manifest 绝对路径content
(optional): 请求到模块 id 的映射 (默认值为manifest.content
)name
(optional): dll 暴露的地方的名称 (默认值为manifest.name
) (可参考externals
)scope
(optional): dll 中内容的前缀sourceType
(optional): dll 是如何暴露的 (libraryTarget)
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require("../libs/libs-mainfest.json") // 指向生成的manifest.json
}),
通过引用 dll 的 manifest 文件来把依赖的名称映射到模块的 id 上,之后再在需要的时候通过内置的 __webpack_require__
函数来 require
他们。
3、实现
1⃣️.创建webpack.dll.conf.js配置文件
var path = require('path')
var webpack = require('webpack')
var AssetsPlugin = require('assets-webpack-plugin')
var CleanWebpackPlugin = require('clean-webpack-plugin')
var config = require('../config')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var env = config.build.env
module.exports = {
entry: {
libs: [
'vue-router',
'vuex',
'd3',
'jointjs',
'element-ui',
'echarts',
'moment',
'pusher-js',
'lodash'
],
},
output: {
path: path.resolve(__dirname, '../libs'),
filename: '[name].[chunkhash:7].js',
library: '[name]_library',
},
plugins: [
new webpack.DefinePlugin({
'process.env': env,
}),
new webpack.DllPlugin({
path: path.resolve(__dirname, '../libs/[name]-mainfest.json'),
name: '[name]_library',
context: __dirname, // 执行的上下文环境,对之后DllReferencePlugin有用
}),
// 将包或包中的文本提取到单独的文件中
new ExtractTextPlugin('[name].[contenthash:7].css'),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
}),
// 使用Webpack时,您可能希望生成包含生成哈希的包(用于缓存清除)。
// 此插件输出一个json文件,其中包含生成的资源的路径,以便您可以从其他位置找到它们
new AssetsPlugin({
filename: 'bundle-config.json',
path: './libs',
}),
// 用于在构建之前删除/清除构建文件夹
// verbose: true,将日志写入控制台
new CleanWebpackPlugin(['libs'], {
root: path.join(__dirname, '../'), // 绝对路径
verbose: true,
dry: false,
}),
],
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
},
],
},
}
2⃣️、创建build-dll.js文件
var path = require("path")
var webpack = require("webpack")
var dllConfig = require("./webpack.dll.conf")
var chalk = require("chalk")
var rm = require("rimraf")
var ora = require("ora") // 一个很好看的 loading 插件
// 配置loading的颜色和显示的信息
var spinner = ora({
color: "green",
text: "building for Dll..."
})
// 开启loading
spinner.start()
rm(path.resolve(__dirname, "../libs"), err => {
if (err) throw err
webpack(dllConfig, function(err, stats) {
spinner.stop()
if (err) throw err
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + "\n\n"
)
console.log(chalk.cyan(" build dll succeed !.\n"))
})
})
3⃣️、在webpack.prod.conf.js添加Dll配置
plugins: [
...
// 增加DllReferencePlugin配置
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require("../libs/libs-mainfest.json") // 指向生成的manifest.json
}),
new HtmlWebpackPlugin({
// 增加两个变量
libJsName: bundleConfig.libs.js,
libCssName: bundleConfig.libs.css,
}),
]
然后copy打包完成的第三方库到dist文件夹下
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, "../libs"),
to: config.build.assetsSubDirectory,
ignore: ["*.json"]
}
]),
4⃣️、在index.html中动态加入打包完成的第三方库
<% if (htmlWebpackPlugin.options.libCssName){ %>
<link rel="stylesheet" href="./static/<%= htmlWebpackPlugin.options.libCssName %>">
<% } %>
<% if (htmlWebpackPlugin.options.libJsName){ %>
<script src="./static/<%= htmlWebpackPlugin.options.libJsName %>"></script>
<% } %>
5⃣️、执行打包第三方库的操作
在package的scripts中添加build:Dll
"scripts": {
// 添加
"build:dll": "node build/build-dll.js"
}
执行 npm run build build:dll即可执行对第三方库的打包操作。
4、总结
Dll打包以后是独立存在的,只要其包含的库没有增减、升级,hash也不会变化,因此线上的dll代码不需要随着版本发布频繁更新。使用Dll打包的基本上都是独立库文件,这类文件有一个特性就是变化不大。只要包含的库没有升级, 增减,就不需要重新打包。这样也提高了构建速度。而且也具有可移植性,如果其他项目需要相同的库,可以直接copy过去。