提升webpack构建速度(二)
分离基础脚本
一、 使用DllPlugin
和DllReferencePlugin
,将不会经常更新的模块提前进行构建(有更新的话再构建一次),每次构建只是针对于变化的模块。总构建时间理论上会减少(视情况而定)。。。
项目结构:
首先在build
文件夹下新增webpack.dll.conf.js
文件:使用DllPlugin
const webpack = require("webpack")
const path = require('path')
const os = require('os')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const resolve = (dir) => path.join(__dirname, '..', dir);
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: require('../config/prod.env')
module.exports = {
entry: {
vendor: ['v-viewer', 'vuescroll', 'vue-i18n', 'bignumber.js'] // 这4个模块不经常更新
},
output: {
path: resolve('dll_static'),
library: '_dll_[name]_[hash]',
filename: '_dll_[name]_[hash].js'
},
plugins: [
// 去除开发环境提醒:You are running Vue in development mode.
new webpack.DefinePlugin({
'process.env': env
}),
new CleanWebpackPlugin(),
new webpack.DllPlugin({
name: '_dll_[name]_[hash]', //和output.library中一致,值就是输出的manifest.json中的 name值
path: path.join(__dirname, '../dll_static', '[name].manifest.json')
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: true,
drop_debugger: true,
drop_console: true
}
},
sourceMap: false,
parallel: os.cpus().length - 1
}),
]
}
在webpack.base.conf.js
文件中加入:使用DllReferencePlugin
plugins: [
// 引用动态链接库
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll_static/vendor.manifest.json')
}),
]
package.json
文件scripts
中新增一项 "build:dll": "webpack --config build/webpack.dll.conf.js"
在项目根目录下运行 npm run build:dll
后,会生成dll_static
文件夹:包括所有模块(js)和映射关系文件(json),如项目结构图中的dll_static
。由于这些dll.js没有包含在bundle.js中,我们在入口文件中直接用是会报错的,我们需要将dll.js插入到index.html文件中去(注:需要在bundle.js之前)
- 在构建完成后,手动将dll.js写入index.html文件中去
- 使用
add-asset-html-webpack-plugin
插件 - 修改index.html入口文件(使用
htmlWebpackPlugin.options
)
add-asset-html-webpack-plugin
// 文件动态添加到html中
new AddAssetHtmlPlugin([
{
filepath: path.resolve(__dirname, '../dll_static/*.js'),
outputPath: 'dll_static',
publicPath: 'dll_static',
includeSourcemap: false,
hash: true,
}
]),
// 结果如下
<script type=text/javascript src=./static/js/manifest.a41c74cbe64915cdf684.js></script>
<script type=text/javascript src=./static/js/vendor.7a69e6c902f4c682ee3e.js></script>
<script type=text/javascript src=./static/js/app.65ee13921c33c87b3f8d.js></script>
<script src=static/dll_static/_dll_vendor_9f972cb316fca89ce8c5.js?=9f972cb316fca89ce8c5></script>
这个插件老是将代码插入到body
最底部,导致上述模块undefined
。网上说可以,我目前是没成功。。。
利用htmlWebpackPlugin.options
在webpack.base.conf.js
和webpack.prod.conf.js
文件中加入:
// 注:①
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../dll_static'),
to: config.dev.assetsSubDirectory + '/dll_static',
ignore: ['**/*.json'] // 不复制json文件
}
])
new HtmlWebpackPlugin({
// dll存着dll.js的引用地址
dll: (function () {
let name = require(path.resolve(__dirname, `../dll_static/vendor.manifest.json`)).name
return `static/dll_static/${name}.js`
})()
})
在html-webpack-plugin
的入口文件index.html
文件中写入: <script src="<%= htmlWebpackPlugin.options.dll %>"></script>
,最终效果:
<script src=static/dll_static/_dll_vendor_9f972cb316fca89ce8c5.js></script>
①:我们上文提到的理论构建时间较少,才用
DllPlugin
时候比全量编译构建时间只少了2s-3s左右,原因分析:虽然我们每次不构建dll.js,但是每次构建的时候我们需要复制dll.js到指定目录(dev为以项目根目录起的内存文件系统,dev为硬盘文件系统),我开发用的电脑系统是windows 10,经常性的磁盘占用率100%(机械硬盘),感觉复制dll.js文件占用了好多时间。。。(全量编译时间 - 复制时间 = 2s-3s),其实没减少多少,如果换成ssd的话应该效果会提升。
二、 externals
,使用外部脚本引入方式,需修改index.html
入口文件
修改webpack.base.conf.js
文件
module.exports = {
externals: {
"BMap": "BMap",
'vue': 'Vue',
'vue-router': 'VueRouter',
'vuex': 'Vuex',
'axios':'axios',
'element-ui': 'ElementUI',
'echarts': 'echarts'
},
}
在index.html
文件中引入
// 以cdn引入vue为例
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
总结
其实上边提到的两种方法的思路都是将公共依赖剥离出来,减少webpack构建的文件数量