目录
性能优化主要在三个阶段进行:开发阶段、开发结束后的打包阶段、项目部署上线阶段
首先需要知道性能优化要达到的目的就是让页面加载更快,也就是需要让代码打包后的体积尽可能的小以及让资源请求时机分配更合理
在我独立开发的博客全栈项目也用到了性能优化,在项目开发结束后不进行优化直接部署上线后后台的lighthouse打分只有50多分,性能很差,白屏时间也长,经过一系列的优化后再次部署上线,前台lighthouse跑分100分,后台也有80多分,加载速度有了很大的提升。
前台lighthouse:
后台lighthouse:
性能分析工具
lighthouse
谷歌浏览器自带的开发者工具,在项目部署上线后可以f12找到lighthouse对项目进行跑分,lighthouse不仅能通过评分直观的看到项目的整体性能情况,还能提出项目的性能问题,可以依照提出的问题对项目进行优化
Webpack Bundle分析
webpack中提供了对打包的项目文件体积直观展示的插件webpack-bundle-analyzer
,安装后在vue.config.js中配置,然后在执行了打包命令打包结束后就会自动打开浏览器展示打包的各文件体积,可以直观的看到哪些文件体积过大,也能看到哪些依赖包项目并没有用到却忘了移除,可以通过这个插件去优化项目的包体积
js
// vue.config.js配置
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
],
},
}
效果图:
开发阶段
开发过程中按需引入、懒加载、请求合理化、代码精简等
按需引入
往往一个项目中需要用到很多的第三方依赖,而在开发中也许用不到依赖的所有方法和组件,这时候就需要对第三方依赖进行按需引入,只引入代码中需要用到的组件或方法,以减少打包时的包体积;比如项目中使用element组件库就尽量使用官网提供的按需引入的方法
路由懒加载
SPA中一个很重要的提速手段就是路由懒加载,当打开页面时才去加载对应文件 ,我们利用Vue的异步组件和webpack的代码分割(import()
)就可以轻松实现懒加载了。
但当路由过多时,请合理地用webpack的魔法注释对路由进行分组,太多的chunk会影响构建时的速度
js
// 进入register页面时才会加载对应的路由组件
{
path: 'register',
name: 'register',
component: () => import(/* webpackChunkName: "user" */ '@/views/user/register'),
}
在开发过程中也需要注意合理使用请求,网络请求也是性能优化的一方面,在项目开发过程中需要注意请求的时机,合理分配请求,去除无用请求等
打包阶段
打包配置减少包体积
webpack/vite打包阶段对代码进行压缩、图片压缩、分包、去除无用代码、资源预加载等操作让代码包体积减小以及合理分配资源请求,从而实现部署上线后缩短请求时间等
对webpack/vite进行配置也是性能优化中很重要的一环,通过合理的打包配置可以大幅减少项目包体积。
配置压缩
vue-cli配置图片压缩以及gzip压缩:
js
module.exports = {
// 修改已有的plugins/loader时使用chainWebpack
chainWebpack: config => {
// 压缩图片
// 需要 npm i -D image-webpack-loader
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.9], speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
});
},
// 添加新的plugins/loader以及webpack配置项时使用configureWebpack
configureWebpack: config => {
// 开启 gzip 压缩
// 需要 npm i -D compression-webpack-plugin
const plugins = [];
if (IS_PROD) {
plugins.push(
new CompressionWebpackPlugin({
filename: "[path].gz[query]",
algorithm: "gzip",
test: productionGzipExtensions,
threshold: 10240,
minRatio: 0.8
})
);
}
config.plugins = [...config.plugins, ...plugins];
}
}
vite配置图片压缩、gzip压缩、移除console.log:
js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
//引入gzip压缩
import viteCompression from 'vite-plugin-compression'
//压缩图片
import viteImagemin from 'vite-plugin-imagemin'
// https://vitejs.dev/config/
export default defineConfig({
//配置打包公共根路径
base: "./",
plugins: [
vue(),
//gzip压缩
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz',
}),
//图片压缩
viteImagemin({
gifsicle: {
optimizationLevel: 7,
interlaced: false
},
optipng: {
optimizationLevel: 7
},
mozjpeg: {
quality: 20
},
pngquant: {
quality: [0.8, 0.9],
speed: 4
},
svgo: {
plugins: [
{
name: 'removeViewBox'
},
{
name: 'removeEmptyAttrs',
active: false
}
]
}
})
],
//生产环境配置
build: {
//移除console.log
minify: 'terser', // 默认为esbuild,需要安装terser -D
terserOptions: {
compress: {
// drop_console: true, // 生产环境移除console
// drop_debugger: true // 生产环境移除debugger
}
}
}
})
分包
vue-cli3的默认优化是将所有npm依赖都打进chunk-vendor,但这种做法在依赖多的情况下导致chunk-vendor过大,可以在vue.config.js中配置分包策略,将第三方依赖包单独打包,避免打包后单一文件过大导致请求加载缓慢。
js
optimization: isProd ? {
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity, // 默认为3,调整为允许无限入口资源
minSize: 20000, // 20K以下的依赖不做拆分
cacheGroups: {
vendors: {
// 拆分依赖,避免单文件过大拖慢页面展示
// 得益于HTTP2多路复用,不用太担心资源请求太多的问题
name(module) {
// 拆包
const packageName = module.context.match(/[\/]node_modules[\/](.*?)([\/]|$)/)[1]
// 进一步将Ant组件拆分出来,请根据情况来
// const packageName = module.context.match(/[\/]node_modules[\/](?:ant-design-vue[\/]es[\/])?(.*?)([\/]|$)/)[1]
return `npm.${packageName.replace('@', '')}` // 部分服务器不允许URL带@
},
test: /[\/]node_modules[\/]/,
priority: -10,
chunks: 'initial'
}
}
},
runtimeChunk: { name: entrypoint => `runtime-${entrypoint.name}` }
} : {}
- vue inspect > output.js --mode production 可以查看最终配置
- 分包这块需要根据实际情况做对应处理,才能取得比较好的效果,总之多看文档多试就对了
资源预加载/预请求
标签的rel属性的两个可选值。Prefetch,预请求,是为了提示浏览器,用户未来的浏览有可能需要加载目标资源,所以浏览器有可能通过事先获取和缓存对应资源,优化用户体验。Preload,预加载,表示用户十分有可能需要在当前浏览中加载目标资源,所以浏览器必须预先获取和缓存对应资源。
Prefetch、Preload在某些场景下可以有效优化用户体验。
Vue-Cli3默认会使用preload-webpack-plugin对chunk资源做preload、prefetch处理,入口文件preload,路由chunk则是prefetch。
一般来说不需要做特别处理,如果判断不需要或者需要调整在vue.config.js
中配置即可
部署阶段
服务器部署项目用nginx开启http2、静态资源缓存、资源压缩等减少项目包的请求时间和次数等
项目部署阶段借助nginx也可以对项目性能进行优化。
开启http2
http2有着多路复用和头部信息压缩的特性,项目开启http2可以同时处理多个请求,加快请求时间,开启http2之前需要给项目开启https,具体怎么开启https以及http2可以看我这篇文章:网站使用nginx部署ssl证书开启https(开启http2)
静态资源缓存
nginx还可以配置静态资源缓存,对项目的静态资源配置缓存后在资源第一次请求后会将资源缓存下来,后续就可以直接使用缓存,在缓存到期之前都不会再次请求该静态资源,可以加快资源获取时间
bash
#静态资源缓开启缓存
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
{
# 这里同样需要反向代理,不然请求路径会是haixtx.cn:82,会出现404
proxy_pass http://114.55.75.3:8000;
expires 30d;
}
location ~ .*.(js|css)?$
{
proxy_pass http://114.55.75.3:8000;
expires 12h;
}
gzip压缩
nginx也可以配置gzip压缩,HTTP协议中用头部字段Accept-Encoding
和 Content-Encoding
对「采用何种编码格式传输正文」进行了协定,请求头的Accept-Encoding
会列出客户端支持的编码格式。当响应头的Content-Encoding
指定了gzip时,浏览器则会进行对应解压
一般浏览器都支持gzip,所以Accept-Encoding
也会自动带上gzip
,所以我们需要让资源服务器在Content-Encoding
指定gzip,并返回gzip文件
bash
#开启和关闭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;
虽然上面配置后Nginx已经会在响应请求时进行压缩并返回Gzip了,但是压缩操作本身是会占用服务器的CPU和时间的,压缩等级越高开销越大,所以我们通常会一并上传gzip文件,让服务器直接返回压缩后文件,所以还需要在项目打包阶段配置gzip,具体配置上面已经讲过了