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