一、背景
由于旧项目是用vue-cli3脚手架搭建,随着项目代码不断增加,webpack每次热更新都需要编译很久,同时打包构建所需时间也增加了不少,鉴于升级webpack版本会出现各自意想不到的坑,所以决定通过优化webpack配置来提高项目的编译和构建速度,话不多说,开整!!!!!
二、项目环境
本次优化的项目的环境是:node版本14.17.0 npm版本6.14.13
js
package.json 限定了node和npm的版本
"engines": {
"node": ">=14.17.0",
"npm": ">=6.14.13"
},
三、使用Happypack插件
使用该插件的主要目的是因为该插件将任务分解到多个子进程中去并行处理,从而减少总的构建时间。使用配置如下:
js
vue.config.js文件
安装happypack npm install happypack -D
const Happypack = require('happypack')
configureWebpack:{
// 该配置可以提高25%左右的速度
new Happypack({
loaders: ['babel-loader', 'vue-loader', 'url-loader'],
cache: true,
threads: 10 // 线程数取决于你电脑性能的好坏,好的电脑建议开更多线程
})
}
四、使用文件压缩插件 compression-webpack-plugin
该插件的主要作用是压缩文件,可以降低dist包文件大小,配置如下:
js
// 需要压缩的文件
vue.config.js文件
安装compression-webpack-plugin npm install compression-webpack-plugin -D
// 压缩,可以将dist文件由20M压缩到3M
const CompressionPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i
configureWebpack:{
plugins: [
new CompressionPlugin({
test: productionGzipExtensions, // 需要压缩的文件正则
threshold: 10240, // 文件大小大于这个值时启用压缩
deleteOriginalAssets: true // 压缩后保留原文件
})
]
}
五、使用dll
该插件是用于打包一些版本基本不怎么变的第三方库,然后引入到index.html文件里,它的主要作用是缓存和复用代码,以提高构建速度和效率。使用DLL插件可以避免重复打包和编译那些没有改变的或者变化不大的代码,从而提高构建速度和效率。DLL插件的使用可以显著提高大型项目的构建速度,同时也可以减少打包文件的大小。具体使用方式如下
js
安装 npm install --save-dev webpack-dll-plugin
安装 html-include-assets-plugin
// 开启dll
const dllHelper = require('./dllHelper');
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
const HtmlIncludeAssetsPlugin = require('html-include-assets-plugin');
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i
configureWebpack:{
plugins: [
// 开启dll,构建时间可以减短,比HardSourceWebpackPlugin更快,但是每次都需要执行dll命令
...dllHelper.genDllReferences(),
new HtmlIncludeAssetsPlugin({
assets: dllHelper.loadDllAssets(),
append: false
})
]
}
js
新建一个webpack.dll.conf.js文件
安装 clean-webpack-plugin
const path = require('path')
const webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin')
// dll文件存放的目录
const dllPath = 'public/vendor'
module.exports = {
entry: {
// 需要提取的库文件
vue: ["vue", "vue-router", "vuex"],
plugin: ['vxe-table','vxe-table-plugin-antd','ali-oss'],
ui: ['ant-design-vue'],
},
output: {
path: path.join(__dirname, dllPath),
filename: '[name].dll.js',
// vendor.dll.js中暴露出的全局变量名
// 保持与 webpack.DllPlugin 中名称一致
library: '[name]_[hash]'
},
plugins: [
// 清除之前的dll文件
new CleanWebpackPlugin(),
// 设置环境变量
// new webpack.DefinePlugin({
// 'process.env': {
// NODE_ENV: 'production'
// }
// }),
// manifest.json 描述动态链接库包含了哪些内容
new webpack.DllPlugin({
path: path.join(__dirname, dllPath, '[name]-manifest.json'),
// 保持与 output.library 中名称一致
name: '[name]_[hash]',
context: process.cwd()
})
]
}
js
新建dllHelper.js 文件
// config/dllHelper.js
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
const dllConfig = require('./webpack.dll.conf');
// 根据entry生成DllReferencePlugin列表
function genDllReferences() {
return Object.keys(dllConfig.entry).map(
name =>
new webpack.DllReferencePlugin({
manifest: require(path.join(
__dirname,
`./public/vendor/${name}-manifest.json`
))
})
);
}
// 生成dll文件的静态资源路径
function loadDllAssets() {
return fs
.readdirSync(path.resolve(__dirname, 'public/vendor'))
.filter(filename => filename.match(/.dll.js$/))
.map(filename => `vendor/${filename}`);
}
module.exports = {
loadDllAssets,
genDllReferences
};
构建前,我们需要配置dll命令,执行npm run dll 命令,最终dll文件会插入到index.html文件中
"script":{
"dll": "webpack -p --progress --config ./webpack.dll.conf.js"
}
六、使用HardSourceWebpackPlugin,这个插件会比dll要慢一点,主要是设置缓存,提高二次构建的速度
js
安装HardSourceWebpackPlugin npm install HardSourceWebpackPlugin -D
// 缓存
const HardSourceWebpackPlugin =
require('hard-source-webpack-plugin');
configureWebpack:{
plugins: [
// 设置缓存,缺陷在于会占用本地磁盘空间,比dll慢,两个一起用比dll还慢一点点
new HardSourceWebpackPlugin({
//设置缓存目录的路径
//相对路径或者绝对路径
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
//构建不同的缓存目录名称
//也就是cacheDirectory中的[confighash]值
configHash: function(webpackConfig) {
return require('node-object-hash')({sort: false}).hash(webpackConfig);
},
//环境hash
//当loader、plugin或者其他npm依赖改变时进行替换缓存
environmentHash: {
root: process.cwd(),
directories: [],
files: ['package-lock.json', 'yarn.lock'],
},
//自动清除缓存
cachePrune: {
//缓存最长时间(默认2天)
maxAge: 2 * 24 * 60 * 60 * 1000,
//所有的缓存大小超过size值将会被清除
//默认50MB
sizeThreshold: 50 * 1024 * 1024
},
}),
]
}
七、代码分割
js
chainWebpack: (config) => {
//代码分割
config.optimization.splitChunks({
//chunks: 'all'
cacheGroups: {
vendor: {//第三方库抽离
chunks: 'all',
test: /node_modules/,
name: 'vendor',
minChunks: 1,//在分割之前,这个代码块最小应该被引用的次数
maxInitialRequests: 5,
minSize: 0,//大于0个字节
priority: 100//权重
},
common: { //公用模块抽离
chunks: 'all',
test: /[\\/]src[\\/]js[\\/]/,
name: 'common',
minChunks: 2,//在分割之前,这个代码块最小应该被引用的次数
maxInitialRequests: 5,
minSize: 0,//大于0个字节
priority: 60
},
styles: { //样式抽离
name: 'styles',
test: /\.(sa|sc|c)ss$/,
chunks: 'all',
enforce: true
},
runtimeChunk: {
name: 'manifest'
}
}
})
}
八、配置一些loader配置
js
configureWebpack:{
module: {
//如果一些第三方模块没有AMD/CommonJS规范版本,可以使用 noParse 来标识这个模块,
//这样 Webpack 会引入这些模块,但是不进行转化和解析,从而提升 Webpack 的构建性能 ,例如:jquery 、lodash。
noParse: /^(lodash|moment|xe-utils|xlsx|ali-oss)$/,
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
// 开启缓存
cacheDirectory: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
]
}
}
九、开启文件变化监听,速度提升不算很大,在大型项目比较有用
js
chainWebpack: (config) => {
if (process.env.NODE_ENV !== 'production') {
config.watch(true)
config.watchOptions(
{
// 排除监听文件
ignored: /node_modules/,
// 在监听到文件变化后等待一段时间再执行编译
aggregateTimeout: 300, // 300ms
// 开启轮询
poll: 100
}
)
}
}
总结:以上配置可以按需选择,并不一定所有配置都需要用上,选择你觉得对你项目效果比较明显的即可。