优化前需要安装的两个分析工具
1. webpack-bundle-analyzer: 用于分析打包后包大小
2. speed-measure-webpack-plugin: 可以输出各个模块的编译时长,可以帮助我们更好的找到耗时较大的模块
vue脚手架的两个配置方式
1. configureWebpack: 修改已有的webpack配置,通过对象/函数的方式进行配置,方便快捷
2. chainWepack: 这是一种较为灵活的配置方式,可以对webpack配置进行修改,可以利用提供的api进行更加精细的颗粒度配置(api看得懂就行,可以联合inspect生成的配置进行搭配使用)
生成配置文件,提供参考学习
package.json:
"inspect": "vue inspect > webpack.config.production.js --mode production"
npm install inspect可以在根目录生成webpack.config.production.js
该配置中就有链式调用的相关代码
1-进入正题,使用webpack-bundle-analyzer和speed-measure-webpack-plugin
- 使用configWebpack 函数方式(对象更简单,这里只是我试用一下) ``
configureWebpack: config => {
if (process.env.NODE_ENV == 'production') {
config.plugins.push(
// 依赖分析
new BundleAnalyzerPlugin({
analyzerPort: 8880 // 端口号
}),
new SpeedMeasurePlugin()
)
}
}
-----也可以,但是不推荐,简单的添加插件,就直接放在configureWebpack-----
chainWebpack: config => {
config
.plugin('speed-measure-plugin')
.use(new SpeedMeasurePlugin())
config
.plugin('webpack-bundle-analyzer')
.use(new BundleAnalyzerPlugin({
analyzerPort: 8880
}))
}
- 按需加载Element
依赖npm install babel-plugin-component -D
babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
- 打包后的文件大小
2. 使用CDN
vue.config.js
const cdn = {
externals: {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
},
js: [
'http://lib.baomitu.com/vue/2.6.14/vue.min.js',
'http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js',
'https://lib.baomitu.com/axios/1.3.4/axios.min.js'
]
}
productionSourceMap: false // 去掉map
configureWebpack: config => {
config.externals = cdn.externals
}
// 颗粒度配置放在chainWebpack
chainWebpack: config => {
// 注入变量,方便在html模板中使用
config
.plugin('html')
.tap((args) => {
args[0].mode = 'prod'
args[0].cdn = cdn
return args
})
}
index.html
// 判断是否生产模式,也可以直接用process.env.NODE_ENV
<% if (htmlWebpackPlugin.options.mode === 'prod') { %>
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
<% } %>
体积变小了,打包速度也更快了
注意:
- 线上项目不推荐使用公共CDN,因为不稳定,可以放在自家公司购买的cdn服务上
- 把资源拆除去用cdn加载,完全不走treeshaking
3. thread-loader 开启多线程优化
vuecli5的配置parallel:是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建,默认为false,以下是开启后的耗时
根据speed-measure-webpack-plugin的分析,可以针对某些耗时长的模块使用thread-loader
const oneOfsMap = config.module.rule('scss').oneOfs.store
oneOfsMap.forEach(item => {
item
.use('thread-loader')
.before('mini-css-extract-plugin')
.loader('thread-loader')
.options({
workers: require('os').cpus().length - 1
})
.end()
})
根据图可以见,并不是一味加thread-loader就可以减少打包时间,因为开启多进程打包也是有消耗的,所以这个需要看自己的项目再决定使不使用,因为我这文件模块比较小,也就耗时2秒多,没什么必要开启,单纯做演示
这里是其他版本的vuecli配置方式,本文用的vuecli5
4. 使用缓存优化
cache-loader
hard-source-webpack-plugin
babel-loader的cacheDirectory标志
以上这些缓存方式都有首次启动时的开销,即它们会让 "冷启动" 时间会更长,但是二次启动能够节省很多时间.
而 vue-cli 已经内置了 cache-loader
和 babel-loader 的 cacheDirectory 标志
,其中对应的配置如下:(vue-cli5版本没发现内置cache-loader)
这里cache-loader
hard-source-webpack-plugin
就不做演示了~因为项目不大,效果看不太出来
5. 去掉console,减少代码体积
webpack v5 开箱即带有最新版本的 terser-webpack-plugin
,vuecli5就是基于webpack5的
也可以通过 uglifyjs-webpack-plugin
插件(webpack5不推荐使用,推荐用terser-webpack-plugin)来删除注释和压缩 js 代码
chainWebpack: config => {
// 去除console
config
.optimization
.minimizer('terser')
.use(require('terser-webpack-plugin'), [{
terserOptions: {
compress: {
drop_console: true
},
output: {
comments: false
}
}
}])
}
6. 图片压缩
所需依赖image-webpack-loader
chainWebpack: config => {
// 压缩图片
config
.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: [0.65, 0.90],
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
})
}
7. gzip压缩
两种gzip压缩的方式:
1、打包的时候通过webpack配置生成对应的 .gz 文件,浏览器请求xx.js/css等文件时,服务器返回对应的xxx.js.gz文件;
2、浏览器请求xx.js文件时,服务器对xx.js文件进行gzip压缩后传输给浏览器。
这里介绍第二种 安装依赖compression-webpack-plugin
npm install compression-webpack-plugin --save-dev
const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: config => {
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip', // 使用gzip压缩
test: /\.js$|\.html$|\.css$/, // 匹配文件名
filename: '[path].gz[query]', // 压缩后的文件名(保持原文件名,后缀加.gz)
minRatio: 1, // 压缩率小于1才会压缩
threshold: 10240, // 对超过10k的数据压缩
deleteOriginalAssets: false, // 是否删除未压缩的源文件,谨慎设置,如果希望提供非gzip的资源,可不设置或者设置为false(比如删除打包后的gz后还可以加载到原始资源文件)
})
)
}