项目打包体积大,页面首屏加载时间过长,导致页面白屏。因此进行性能优化,性能优化的最终目的是提升用户体验。
1、BundleAnalyzer
作用:展示打包图形化信息,会打开一个html页面,帮助自己分析哪些文件过大,可针对其进行优化,上线前 注释掉
// 安装 webpack-bundle-analyzer 插件
npm install webpack-bundle-analyzer -D
// 在 vue.config.js: 里面:
// 引入
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
// 展示图形化信息
chainWebpack: config => {
config
.plugin('webpack-bundle-analyzer')
.use(BundleAnalyzerPlugin)
}
// 查看
npm run build --report
2、排查并移除冗余依赖、静态资源
- 移除项目模板冗余依赖
- 将public的静态资源移入assets。静态资源应该放在assets下,public只会单纯的复制到dist,应该放置不经webpack处理的文件,比如不兼容webpack的库,需要指定文件名的文件等
3、压缩CSS(mini-css-extract-plugin)
// 安装 mini-css-extract-plugin 插件
npm install mini-css-extract-plugin -D
// 在 vue.config.js里面:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
chainWebpack: config => {
let miniCssExtractPlugin = new MiniCssExtractPlugin({
filename: 'assets/[name].[hash:8].css',
chunkFilename: 'assets/[name].[hash:8].css'
})
config.plugin('extract-css').use(miniCssExtractPlugin)
}
// 在module.exports下添加,否则在打包过程出现 报错没有可用于依赖类型的模块 CssDependency
css: {
extract: false
}
4、构建时压缩图片(image-webpack-loader)
- install或build时如果出现imagemin库下载失败,可以尝试换源、配置github hosts、install时添加–user=root解决。
本人使用cnpm安装成功
- 卸载插件时注意,npm和cnpm混用卸载回起冲突,使用npm卸载之后
compression-webpack-plugin
插件不能使用
// 安装前请先查看上面的两点 install
npm i image-webpack-loader -D
// vue.config.js
chainWebpack: (config) => {
if (isProd) {
// 图片压缩处理
const imgRule = config.module.rule('images')
imgRule
.test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
}
}
5、js压缩(uglifyjs-webpack-plugin)
// 安装 uglifyjs-webpack-plugin 插件
npm install uglifyjs-webpack-plugin -D
// 在 vue.config.js里面
chainWebpack: (config) => {
config.plugin('uglifyjs-plugin').use('uglifyjs-webpack-plugin', [
{
uglifyOptions: {
warnings: false,
// 生产环境自动删除console
compress: {
dead_code: true, // 移除没被引用的代码
drop_debugger: true, // 移除 debugger
drop_console: true, // 移除console函数
pure_funcs: ['console.log']
}
},
sourceMap: false,
cache: false, // 是否启用文件缓存,默认的缓存路径为: node_modules/.cache/uglifyjs-webpack-plugin.
parallel: true // 使用多进程并行运行来提高构建速度
}
])
}
6、terser简化表达式和函数等方式来减小代码体积
terser 会通过简化表达式和函数等方式来减小代码体积,和加快运行时的速度、减少运行时内存占用
// 在 vue.config.js里面
chainWebpack: (config) => {
config.optimization.minimizer('terser').tap(args => {
args[0] = {
test: /\.m?js(\?.*)?$/i,
chunkFilter: () => true,
warningsFilter: () => true,
extractComments: false, // 注释是否单独提取成一个文件
sourceMap: true,
cache: true,
cacheKeys: defaultCacheKeys => defaultCacheKeys,
parallel: true,
include: undefined, // 对哪些文件生效
exclude: undefined,
minify: undefined, // 自定义minify函数
// 完整参数见 https://github.com/terser/terser#minify-options
terserOptions: {
compress: {
arrows: true, // 转换成箭头函数
collapse_vars: false, // 可能有副作用,所以关掉
comparisons: true, // 简化表达式,如:!(a <= b) → a > b
computed_props: true, // 计算变量转换成常量,如:{["computed"]: 1} → {computed: 1}
drop_console: true, // 去除 console.* 函数
hoist_funs: false, // 函数提升声明
hoist_props: false, // 常量对象属性转换成常量,如:var o={p:1, q:2}; f(o.p, o.q) → f(1, 2);
hoist_vars: false, // var声明变量提升,关掉因为会增大输出体积
inline: true, // 只有return语句的函数的调用变成inline调用,有以下几个级别:0(false),1,2,3(true)
loops: true, // 优化do, while, for循环,当条件可以静态决定的时候
negate_iife: false, // 当返回值被丢弃的时候,取消立即调用函数表达式。
properties: false, // 用圆点操作符替换属性访问方式,如:foo["bar"] → foo.bar
reduce_funcs: false, // 旧选项
reduce_vars: true, // 变量赋值和使用时常量对象转常量
switches: true, // 除去switch的重复分支和未使用部分
toplevel: false, // 扔掉顶级作用域中未被使用的函数和变量
typeofs: false, // 转换typeof foo == "undefined" 为 foo === void 0,主要用于兼容IE10之前的浏览器
booleans: true, // 简化布尔表达式,如:!!a ? b : c → a ? b : c
if_return: true, // 优化if/return 和 if/continue
sequences: true, // 使用逗号运算符连接连续的简单语句,可以设置为正整数,以指定将生成的最大连续逗号序列数。默认200。
unused: true, // 扔掉未被使用的函数和变量
conditionals: true, // 优化if语句和条件表达式
dead_code: true, // 扔掉未被使用的代码
evaluate: true // 尝试计算常量表达式
// passes: 2, // compress的最大运行次数,默认是1,如果不在乎执行时间可以调高
},
mangle: {
safari10: true
}
}
}
return args
})
}
7、代码分块
首屏加载文件太大,将文件分割出来
// 在 vue.config.js里面
chainWebpack: (config) => {
config.optimization.splitChunks({
chunks: 'all',
maxInitialRequests: 5, // 默认3
maxAsyncRequests: 6, // 默认5
cacheGroups: {
commons: {
name: 'chunk-commons',
chunks: 'initial',
test: resolve('src/components'), // can customize your rules
minChunks: 2, // 表示被引用次数,默认为1
maxInitialRequests: 5, // 一个入口最大的并行请求数,默认为3
minSize: 60000, // 大小超过60kb的模块才会被提取,防止一堆小chunck
priority: 1,
reuseExistingChunk: true,
enforce: true
},
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 2,
reuseExistingChunk: true, // 如果当前代码块包含的模块已经有了,就不在产生一个新的代码块
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 3, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
reuseExistingChunk: true,
enforce: true
},
agoraRtcSdkNg: {
name: 'chunk-agora-rtc-sdk-ng', // split elementUI into a single package
priority: 4, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?agora-rtc-sdk-ng(.*)/, // in order to adapt to cnpm
reuseExistingChunk: true,
enforce: true
},
}
})
}
8、Gzip压缩传输(compression-webpack-plugin)
Gzip压缩是一种强力压缩手段,针对文本文件时通常能减少2/3的体积。
Nginx配置Gzip
#开启和关闭gzip模式
gzip on;
#gizp压缩起点,文件大于1k才进行压缩
gzip_min_length 1k;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间
gzip_comp_level 6;
# 进行压缩的文件类型。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ;
# nginx对于静态文件的处理模块,开启后会寻找以.gz结尾的文件,直接返回,不会占用cpu进行压缩,如果找不到则不进行压缩
gzip_static on;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 设置gzip压缩针对的HTTP协议版本
gzip_http_version 1.1;
构建时生成gzip文件
虽然上面配置后Nginx已经会在响应请求时进行压缩并返回Gzip了,但是压缩操作本身是会占用服务器的CPU和时间的,压缩等级越高开销越大,所以我们通常会一并上传gzip文件,让服务器直接返回压缩后文件
不要使用最新版本
,使用最新版本会报错- 插件的默认压缩等级是9,最高级的压缩
- 图片文件不建议使用gzip压缩,效果较差
// 安装 compression-webpack-plugin 插件 (不要使用最新版本)
npm i compression-webpack-plugin@6.1.1 -D
// vue.config.js
const CompressionPlugin = require('compression-webpack-plugin')
// gzip压缩处理
chainWebpack: (config) => {
if(isProd) {
config.plugin('compression-webpack-plugin')
.use(new CompressionPlugin({
test: /\.js$|\.html$|\.css$/, // 匹配文件名
threshold: 10240, // 对超过10k的数据压缩
deleteOriginalAssets: false // 不删除源文件
}))
}
}