DLL(Dynamic Link Library)文件爲動態連接庫文件,在Windows中,許多應用程序並非一個完整的可執行文件,它們被分割成一些相對獨立的動態連接庫,即DLL文件,放置於系統中。當咱們執行某一個程序時,相應的DLL文件就會被調用。javascript
在項目中第三方的代碼庫就是獨立的連接庫,咱們每次打包的時候都會將這些庫進行和咱們本身編寫的代碼同樣的編譯壓縮檢查等等工做,dll就是能夠把這些第三方的庫放在一塊兒單獨打包,不須要每次都打包css
webpack 使用dll的方式是由兩個插件完成的html
DllPluginjava
DllReferencePluginreact
const webpack = require('webpack');
const path = require('path');
const vendor = [
'react',
'react-dom',
'react-router',
'react-router-dom',
// 其餘插件
'react-transition-group',
'prop-types',
'classnames',
'history'
];
module.exports = {
output: {
path: path.resolve(__dirname, './dll'), // js 存放的地方
filename: '[name].js', // name -> 'verdor'
library: '[name]',
},
entry: {
vendor: vendor
},
plugins: [
new webpack.DllPlugin({
path: 'manifest.json',
name: '[name]', // 和上面的library同樣就行
}),
],
};
複製代碼
在package.json的scripts中添加運行這個文件的命令:jquery
"dll": "webpack --config dll.base.js"
複製代碼
會在項目目錄下產生dll文件夾和manifest.json文件,dll中有vendor.js,manifest.json有兩個屬性 name文件名,content: 含有的的module信息webpack
2.在正常生產打包過程當中,經過DllReferencePlugin將打包好的庫和剩下的須要編譯的代碼在module依賴上結合起來git
webpack.config.js 中pluging 配置,注意只需在生產環境配置這插件github
plugins: [
new webpack.DllReferencePlugin({
manifest: require("./manifest.json"), // dll 中生成的json 文件
}),
],
複製代碼
在沒有添加這個plugin的時候,build過程用時4767ms,打包200個module,budle.js 大小201kb 添加DllReferencePlugin後, 用時3195ms,打包175個module, bundle.js 大小41kb 打包完的htmlweb
<!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>React and Webpack4</title>
<link href="app.css" rel="stylesheet"></head>
<body>
<section id="index"></section>
<script type="text/javascript" src="app.bundle.js"></script></body>
</html>
複製代碼
能夠看到只有bundle.js 這個引用,沒有vendor.js,須要用到HtmlWebpackPlugin 插件裏面的inject功能
const Manifest = require('./manifest.json');
const htmlPlugin = new HtmlWebpackPlugin({
template: './src/index.html',
filename: './index.html',
vendorName: '../dll/'+Manifest.name + '.js',
inject: true
});
複製代碼
template.html
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.vendorName %>"></script>
複製代碼
vendorName就是引用的完整的路徑
dll中的文件須要鎖定版本,不能使用對應的contenthash 打包的第三方js不可以加上文件名上的hash,能夠在每次發新版的時候生成hash拼接query的方式解決,不過這種方式須要另外增長代碼,而且多人合做時不必定能有效控制每一個包的版本。
兩種以上的dll包使用起來麻煩
若是項目中有不少的第三方代碼(mvc庫,UI庫及其相關的庫,圖表圖(通常都很大),相應的poly-fill(兼容性代碼))若是都打包到一塊兒就會是很大的一個文件,這時會經過分開打包讓瀏覽器可以並行下載這些文件的方式來加快加載速度。 下面dll代碼會生成相應的三個dll文件 r1,t1,t2. 文件名是contenthash
const entry = {
// react相關
r1: [
'react',
'react-dom',
...
],
// bizchart
t1: [
'bizcharts',
],
// 其餘1
t2: [
'jquery',
'moment',
'babel-polyfill',
'proxy-polyfill'
],
// // 其餘2
// t3: [
// ''
// ]
};
module.exports = {
output: {
path: rootPath,
filename: 'dll.[name]-[contenthash].js',
library: '[name]',
},
entry,
複製代碼
plugin.push(
new Webpack.DllReferencePlugin({
manifest: require(r1的manifest json 的path), // dll 中生成的json 文件
}),
new Webpack.DllReferencePlugin({
manifest: require(t1的manifest json 的path), // dll 中生成的json 文件
}),
new Webpack.DllReferencePlugin({
manifest: require(t2的manifest json 的path), // dll 中生成的json 文件
})
)
複製代碼
plugin [
new HTMLWebpackPlugin({
template: './index.html',
r1: 'dll文件夾path/r1.js',
t1: 'dll文件夾path/t1.js',
t2: 'dll文件夾path/t2.js',
});
]
複製代碼
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.r1%>"></script>
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.t1 %>"></script>
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.t2 %>"></script>
複製代碼
其實多文件dll的build過程就是,Webpack.DllReferencePlugin中把生成的每一個json添加這個插件一次,在html添加上對應的文件名稱和路徑。
var getDllConfigs = (dllPath) => {
const result = [];
var walk = function (dir) {
var results = []
var list = fs.readdirSync(dir)
list.forEach(function (file) {
file = dir + '/' + file
var stat = fs.statSync(file)
if (stat && stat.isDirectory()) results = results.concat(walk(file))
else results.push(file)
});
return results
};
const dllFiles = walk(dllPath);
dllFiles.forEach((filePath) => {
if (path.extname(filePath) === '.json') {
result.push({
manifest: require(filePath), // dll 中生成的json 文件
});
}
});
return result;
};
getDllConfigs(dll_path).forEach(item => {
WebpackBaseConfig.plugins.push(new Webpack.DllReferencePlugin(item))
});
複製代碼
//insert html
var fs = require('fs');
var path = require('path');
var walk = function (dir) {
var results = []
var list = fs.readdirSync(dir)
list.forEach(function (file) {
file = dir + '/' + file
var stat = fs.statSync(file)
if (stat && stat.isDirectory()) results = results.concat(walk(file))
else results.push(file)
});
return results
};
function insertHtmlDllPlugin(options) {
this.options = options;
}
insertHtmlDllPlugin.prototype.apply = function (compiler) {
var self = this;
// webpack 4 support
compiler.hooks.compilation.tap('insertHtmlDllPlugin', (compilation) => {
compilation.hooks.htmlWebpackPluginAfterHtmlProcessing.tapAsync('insertHtmlDllPlugin', (htmlPluginData, callback) => {
self.onAfterHtmlProcessing(htmlPluginData, callback);
});
});
}
insertHtmlDllPlugin.prototype.onAfterHtmlProcessing = function (htmlPluginData, callback) {
var enable = typeof this.options.enable !== 'undefined' ? this.options.enable : true;
if (!enable) {
return;
}
var dllPath = this.options.dllPath;
if (!dllPath || !fs.existsSync(path.resolve(dllPath))) {
throw new Error('dll path don\'t exist');
}
// 遍歷dll文件夾找到對應的js,寫入html的header中
var dllFiles = walk(dllPath);
var scriptsStr = '';
var publicPath = this.options.publicPath || '';
dllFiles.forEach((filePath) => {
const fileName = path.basename(filePath);
if(path.extname(filePath) === '.js'){
scriptsStr += '<script type="text/javascript" src="' + (publicPath + fileName) + '"></script>';
}
});
//
console.log(this.options);
htmlPluginData.html = htmlPluginData.html.replace('</head>', scriptsStr + '</head>');
callback(null, htmlPluginData);
};
module.exports = insertHtmlDllPlugin;
複製代碼
將全部的js寫入head 標籤中
2.demo