本文介绍了 Webpack 中 DllPlugin 插件的使用,以及配合使用 AddAssetHtmlPlugin 将构建好的 JS 文件插入到 html 页面中。html
本文项目代码位置:源码地址node
欢迎 Star!react
DLLPlugin 就是将包含大量复用模块且不会频繁更新的库进行编译,只须要编译一次,编译完成后存在指定的文件(这里能够称为动态连接库)中。在以后的构建过程当中不会再对这些模块进行编译,而是直接使用 DllReferencePlugin 来引用动态连接库的代码。所以能够大大提升构建速度。通常会对经常使用的第三方模块使用这种方式,例如 react、react-dom、lodash 等等。只要这些模块不升级更新,这些动态连接库就不须要从新编译。webpack
Webpack 已经内置了对动态连接库的支持,须要经过两个内置插件的配合使用。它们分别是:git
# 建立项目目录
$ mkdir webpack-dll-demo
# 初始化 package.json 文件
$ npm init -y
# 建立 src 文件夹
$ mkdir src
# 建立 public 文件夹
$ mkdir public
# 安装须要用到的插件
$ npm install webpack webpack-cli html-webpacl-plugin clean-webpacl-plugin friendly-errors-webpack-plugin -D
# 安装 lodash 插件,用于演示 DllPlugin 用法
$ npm install lodash
复制代码
index.htmlgithub
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Webpak DllPlugin 的使用</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
复制代码
index.jsweb
import { join } from 'lodash';
function createSpan(){
const element = document.createElement('span');
element.innerHTML = join(['Hello', 'DllPlugin'], ' , ');
return element;
}
document.querySelector('#root').appendChild(createSpan());
复制代码
webpack-prod-demo
|- /public
|- index.html
|- /src
|- index.js
|- package.json
复制代码
webpack_dll.config.jsnpm
const path = require('path');
const webpack = require('webpack');
const CleanWebpaclPlugin = require('clean-webpack-plugin');
const FirendlyErrorePlugin = require('friendly-errors-webpack-plugin');
module.exports = {
mode: 'production',
entry: {
// 将 lodash 模块做为入口编译成动态连接库
lodash: ['lodash']
},
output: {
// 指定生成文件所在目录
// 因为每次打包生产环境时会清空 dist 文件夹,所以这里我将它们存放在了 public 文件夹下
path: path.resolve(__dirname, 'public/vendor'),
// 指定文件名
filename: '[name].dll.js',
// 存放动态连接库的全局变量名称,例如对应 lodash 来讲就是 lodash_dll_lib
// 这个名称须要与 DllPlugin 插件中的 name 属性值对应起来
// 之因此在前面 _dll_lib 是为了防止全局变量冲突
library: '[name]_dll_lib'
},
plugins: [
new CleanWebpaclPlugin(['vendor'], {
root: path.resolve(__dirname, 'public')
}),
new FirendlyErrorePlugin(),
// 接入 DllPlugin
new webpack.DllPlugin({
// 描述动态连接库的 manifest.json 文件输出时的文件名称
// 因为每次打包生产环境时会清空 dist 文件夹,所以这里我将它们存放在了 public 文件夹下
path: path.join(__dirname, 'public', 'vendor', '[name].manifest.json'),
// 动态连接库的全局变量名称,须要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 lodash.manifest.json 中就有 "name": "lodash_dll_lib"
name: '[name]_dll_lib'
})
]
}
复制代码
webpack.config.jsjson
const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CleanWebpaclPlugin = require('clean-webpack-plugin');
const FirendlyErrorePlugin = require('friendly-errors-webpack-plugin');
module.exports = {
mode: 'production',
devtool: 'source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build-[hash:5].js'
},
plugins: [
new HTMLWebpackPlugin({
title: 'Webpak DllPlugin 的使用',
template: './public/index.html'
}),
new CleanWebpaclPlugin(['dist']),
new FirendlyErrorePlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
// 告诉 Webpack 使用了哪些动态连接库
new webpack.DllReferencePlugin({
// 描述 lodash 动态连接库的文件内容
manifest: require('./public/vendor/lodash.manifest.json')
})
]
}
复制代码
因为动态连接库咱们通常只编译一次,以后就不用编译,复用模块都被打包到了动态连接库中,所以入口的 index.js 文件中已经不包含这些模块了,因此要在 index.html 中单独引入。数组
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Webpak DllPlugin 的使用</title>
</head>
<body>
<div id="root"></div>
<script src="../public/vendor/lodash.dll.js"></script>
</body>
</html>
复制代码
注意:因为在打包项目的时候会清理掉 dist 文件,因此我将生成的动态连接库放到了 public 目录下,因此这里是引入 public 下的动态连接库。
咱们在 package.json 中添加两条指令:
package.json
...
"scripts": {
"build": "webpack --config webpack.config.js",
"build:dll": "webpack --config webpack_dll.config.js"
}
...
复制代码
根据上面所说的三个步骤,Dll 的用法已经结束了。如今咱们运行一下看看结果。
打开命令行,执行命令
# 生成动态连接库,只须要运行一次这个指令,之后打包项目不须要再执行这个指令
$ npm run build:dll
# 打包项目
$ npm run build
复制代码
在浏览器中打开 dist 文件夹下的 index.html 文件,能够看到浏览器上出现:Hello , DllPlugin。说明项目配置成功。
运行 npm run build:dll
指令以后,能够看到项目中 public 目录下多出了一个 vendor 的文件夹,能够看到其中包含两个文件:
lodash.dll.js
里面包含 lodash
的基础运行环境,也就是 lodash 模块lodash.manifest.json
也是由 DllPlugin 生成出,用于描述动态连接库文件中包含哪些模块var lodash_dll_lib=... // 此处代码过多,进行省略
复制代码
{"name":"lodash_dll_lib","content":{"./node_modules/lodash/lodash.js":{"id":1,"buildMeta":{"providedExports":true}},"./node_modules/webpack/buildin/global.js":{"id":2,"buildMeta":{"providedExports":true}},"./node_modules/webpack/buildin/module.js":{"id":3,"buildMeta":{"providedExports":true}}}}
复制代码
对比以后能够明白:
一个动态连接库文件中包含了大量模块的代码,这些模块存放在一个数组里,用数组的索引号做为 ID。 而且还经过 lodash_dll_lib 变量把本身暴露在了全局中,也就是能够经过 window.lodash_dll_lib 能够访问到它里面包含的模块
manifest.json 文件清楚地描述了与其对应的 dll.js 文件中包含了哪些模块,以及每一个模块的路径和 ID
至此,Dll 的使用以及配置完成了。可是这里还有值得思考的地方:目前看来,项目能够正常运行,可是如今动态连接库是存放到 public 目录下的,若是咱们须要将项目打包上线的话,如何可以让动态连接库自动也存放到 dist 目录下呢?如何在咱们不手动添加脚本的状况下,自动将动态连接库引入到 index.html 文件中呢?若是有兴趣的话,能够继续往下来看一看配合 add-asset-html-webpack-plugin 的使用。
上面也已经说了,虽然 Dll 的使用和配置没有问题了,可是还不是很满意,打包的时候不能将动态连接库自动的存放到 dist 文件夹,也不能自动在 html 文件中引入动态连接库脚本。因此这时候 add-asset-html-webpack-plugin 就派上用场了。
$ npm install add-asset-html-webpack-plugin -D
复制代码
在 webpack.config.js 文件中进行使用
webpack.config.js
...;
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
...,
plugins: [
...,
// 该插件将把给定的 JS 或 CSS 文件添加到 webpack 配置的文件中,并将其放入资源列表 html webpack插件注入到生成的 html 中。
new AddAssetHtmlPlugin([
{
// 要添加到编译中的文件的绝对路径,以及生成的HTML文件。支持globby字符串
filepath: require.resolve(path.resolve(__dirname, 'public/vendor/lodash.dll.js')),
// 文件输出目录
outputPath: 'vendor',
// 脚本或连接标记的公共路径
publicPath: 'vendor'
}
])
]
}
复制代码
此时能够删除 index.html 文件中手动引入的脚本了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Webpak DllPlugin 的使用</title>
</head>
<body>
<div id="root"></div>
<!-- 删除下面这行引入脚本 -->
- <script src="../public/vendor/lodash.dll.js"></script>
</body>
</html>
复制代码
打开命令行,执行命令:
# 打包项目
$ npm run build
复制代码
如今查看项目中 dist 文件夹,能够看到 public 目录下 vendor 文件夹中的 js 文件已经所有自动拷贝到 dist 目录中的 vendor 文件夹下了
打开 dist 文件夹中的 index.html 文件,能够看到已经自动将生成的脚本文件引入了
在浏览器中打开 index.html,能够看到 'Hello , DllPlugin' 也可以正常显示
add-asset-html-webpack-plugin 更多配置请参考 github 地址:AddAssetHtmlPlugin 配置
Dll 动态连接库的使用能够提升项目构建速度,由于对于大量复用的模块能够提早进行编译,且只须要编译一次,以后的开发中,使用这些模块的地方都不会再从新进行编译
DllPlugin 和 DllReferencePlugin 须要配合使用
可使用 AddAssetHtmlPlugin 将生成的动态连接库文件拷贝到出口文件夹下,而后 HTMLWebpackPlugin 就会自动的将脚本文件注入到生成的 html 文件中去
**注意:**如想测试一下构建速度是否有提高,能够将 webpack.config.js
中的 DllReferencePlugin 和 AddAssetHtmlPlugin 使用注释起来,运行 npm run build
,观察打包时间;再将注释打开,运行 npm run build
,观察打包时间,进行对比,便可发现区别
如是第一次打包,请先运行
npm run build:dll
生成动态连接库。
本文 Demo 地址:源码地址。 欢迎 Star!