本文介紹了 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!