前端性能优化
优化方式分类 1、免费
包体积 ng配置 缓存 代码压缩 gzip,webpack、vite压缩 最小化HTTP请求、响应大小 JavaScript中的性能优化,1.避免JS动画 2.节流(滚动加载、提交按钮)和防抖(搜索、鼠标移动,窗口resize) 图片懒加载 使用CSS3 代替图片 提取公共代码
2、花费 cdn 带宽 cpu/mem
背景
为满足不同企业对系统登录页个性化设计,且需要独立域名访问的要求,另外合同层面及部署层面强要求,将页面进行拆分部署,以达到合规目的。
遂将原有应用一分为二,将登录页独立部署(每新增一个企业使用,独立部署一套个性化UI的登录NG),所有访问请求需通过登录页ng进行代理。
考虑到每个企业的部署成本,需给出该部署架构下登录页节点的最优资源配置;为找到最合理的部署资源配置参数,我们将对系统进行压测以获取CPU、内存的部署资源参数。
压测目的&体验目标
- 为节省腾讯云部署资源,找出最优资源配置;
根据架构师按用户使用情况进行预估,给到的最大并发10,合理并发5,通过压测工具jmeter进行测试; 将资源不断减半压缩,以测试当前部署架构下,系统的抗压能力,最终找到最低的资源配置参数,以达到降低成本的目的。
渲染目标 FP及FCP 在2秒内完成,体验优秀 LCP(Largest Contentful Paint)代表了页面的速度指标,小于 2.5秒 FID(First Input Delay)代表了页面的交互体验指标,100ms 以内 CLS(Cumulative Layout Shift)代表了页面的稳定指标,0.1或以下
__ 初始部署资源 __
request 1C1G, limit 2C2G
__ 目标部署资源 __
request 0.5C512M,limit 1C1G
压测结果【优化前&优化后】
- 并发测试
测试工具:jmeter
腾讯云环境:单节点测试(开放主机端口进行访问)
测试方法:
- 利用大体积静态资源(JS/CSS)的http请求,预估页面并发下资源加载时长
- 大文件http请求(动态GZIP压缩)JS文件 519K
- 大文件http请求(动态GZIP压缩)css文件 43.6K
- 普通http Get请求
腾讯云资源
优化前
- [测试1] request:1C1G limit:2C2G
- 10并发
- 5并发
- [测试2] request:0.5C512M limit:1C1G
- 10并发
- 5并发
- 10并发
- [测试3] request:0.3C256M limit:0.5C512G
- 10并发
- 5并发
- 10并发
- 页面性能测试 测试工具:Lighthouse
- 优化前
优化思路
影响并发的主要因素有服务器端及客户端的网络、CPU、内存。而影响前端访问性能的因素分为两个部分,加载效率以及运行效率。
加载时优化 1、包体积优化 2、CDN加载 3、GZIP(动态+静态) 4、网络优化,合并请求、减少资源大小
运行时优化 1、减少重排 重绘 2、避免页面卡顿、 3、长列表(虚拟列表)、代码性能、防抖节流
由于项目中体积最大的依赖:UI组件库tdesign只有最新版本的CDN资源,不提供历史版本的CDN,仅优化其他小体积的,改造意义不大。
通过TOP指令监控腾讯云部署节点的CPU/MEM使用情况,观察数据变化分析结果得出,影响低并发的最大因素为网络,而同等带宽下影响下载时长的最大因素为下载资源的体积,所以优化最大资源体积会取得最明显的优化效果。
工程背景
"vue": "2.6.11",
"vite": "2.8.6",
打包优化
依赖包体积检查
bundlejs.com 这样的工具可以用来做快速的检查,但是根据实际的构建设置来评估总是最准确的。
原始打包后静态资源分析
1. 关闭一些打包配置项
- 这个东西一般是在测试阶段调试使用的
build: { terserOptions: { compress: { //生产环境时移除console drop_console: true, drop_debugger: true, }, }, // 关闭文件计算 reportCompressedSize: false, // 关闭生成map文件 可以达到缩小打包体积 sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大 }
2. webpackChunkName 按路由配置moudle合并chunk
引入包vite-plugin-webpackchunkname
,使vite 支持。
配合动态路由配置
优化前 82个文件 优化后 53个文件
- 2.1 装包
yarn -D add vite-plugin-webpackchunkname
- 2.2 配置 vite.config.js ``` js // vite.config.js import { manualChunksPlugin } from ‘vite-plugin-webpackchunkname’ // Other dependencies…
export default defineConfig({ plugins: [ manualChunksPlugin(), ] })
* 说明:Support for user defined manual chunks 支持用户自定义chunks *
#### 3. 拆分依赖包
- 根据依赖包体积进行规划,均匀划分vendor大小,均匀拆分依赖;
- 通过gzip压缩降低2/3 体积。
##### 3.1 vite 相关配置
- 包体积分析
安装依赖
yarn -D add rollup-plugin-visualizer
- 配置分析
plugins: [ vue(), visualizer({ open:true, //注意这里要设置为true,否则无效 gzipSize:true, brotliSize:true }) ],
- 合理分包
```js
/* build.rollupOptions.output.manualChunks */
rollupOptions: {
// input: viteMultiPages,
output: {
manualChunks: (id) => {
if (
id.indexOf('node_modules/lodash/') !== -1 ||
id.indexOf('node_modules/tinycolor2/') !== -1 ||
id.indexOf('node_modules/aegis-web-sdk/') !== -1 ||
id.indexOf('node_modules/sortablejs/') !== -1 ||
id.indexOf('node_modules/@babel/') !== -1 ||
id.indexOf('node_modules/regenerator-runtime/') !== -1 ||
id.indexOf('node_modules/clipboard/') !== -1 ||
id.indexOf('node_modules/dayjs/') !== -1 ||
id.indexOf('node_modules/@popperjs/') !== -1
) {
return 'vendor-utils';
}
if (
id.indexOf('node_modules/core-js/') !== -1 ||
id.indexOf('node_modules/@vue/') !== -1 ||
id.indexOf('node_modules/vue/') !== -1 ||
id.indexOf('node_modules/vue-router/') !== -1 ||
id.indexOf('node_modules/vuex/') !== -1 ||
id.indexOf('node_modules/axios/') !== -1
) {
return 'vendor-core';
}
if (id.indexOf('node_modules/@wecity/') !== -1 || id.indexOf('node_modules/tdesign-icons-vue/') !== -1) {
return 'vendor-tdgv';
}
// if (id.indexOf('node_modules/tdesign-vue/es/') !== -1) {
// return 'vendor-td';
// }
},
},
},
// TODO 打包效果与上面有点差异,暂未分析原因
// if (id.includes('node_modules')) {
// const arr = id.toString().split('node_modules/')[1].split('/');
// switch (arr[0]) {
// case 'lodash':
// case 'lodash-es':
// case 'tinycolor2':
// case 'aegis-web-sdk':
// case 'sortablejs':
// case '@popperjs':
// case '@babel':
// case 'js-base64':
// return 'vendor-utils';
// case 'core-js':
// case '@vue':
// case 'vue':
// case 'vue-router':
// case 'vuex':
// case 'axios':
// return 'vendor-core';
// case '@wecity':
// case 'tdesign-icons-vue':
// return 'vendor-tdgv';
// default:
// return null;
// }
// }
3.2 webpack4 拆包相关配置 SplitChunksPlugin
- 包文件分析
- yarn -D add webpack-bundle-analyzer
- 添加配置
// vue.config.js chainWebpack: (config) => { if (process.env.NODE_ENV === 'production') { config.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin); } }
- 合理拆分module、chunck,配置如下
module.exports = { pages: { index: { ..... ..... // 1、引入新拆分的chunk chunks: ['chunk-vendors', 'vendors-utils', 'vendors-tdgv', 'vendors-core', 'index'] }, }, // 2、webpack4 拆分chunk optimization: { splitChunks: { cacheGroups: { 'vendors-core': { name: 'vendors-core', test: /[\\/]node_modules[\\/](vue|vue-router|axios|@vue|vuex)/, chunks: 'all', priority: 10, enforce: true, }, 'vendors-tdgv': { name: 'vendors-tdgv', test: /[\\/]node_modules[\\/](@wecity|tdesign-icons-vue)/, chunks: 'all', priority: 8, enforce: true, }, 'vendors-utils': { name: 'vendors-utils', test: /[\\/]node_modules[\\/](lodash|tinycolor2|aegis-web-sdk|clipboard|core-js)/, chunks: 'all', priority: 8, enforce: true, }, 'chunk-vendors': { name: 'chunk-vendors', test: /[\\/]node_modules[\\/]/, chunks: 'all', priority: 1, enforce: true, }, }, }, }
4. 静态GZIP
- 4.1 安装依赖
yarn -D add vite-plugin-compression
- 4.2 配置vite.config.js
import compress from 'vite-plugin-compression';
...
defineConfig({
plugins: [
// 压缩10kb以上的文件
compress({ threshold: 10240 }),
...
]
})
命名chunkFileNames
命名chunkFileNames,会额外生成文件,未研究明白。。。
/* build.output.chunkFileNames */
/* 添加一下配置,将按组件文件名 生成chunk 文件 */
output: {
chunkFileNames: (chunkInfo) => {
console.log(`===========${chunkInfo.facadeModuleId}`);
const facadeModuleId = chunkInfo.facadeModuleId ? chunkInfo.facadeModuleId.split('/') : [];
const fileName = facadeModuleId[facadeModuleId.length - 2] || '[name]';
return `${fileName}.[hash].js`;
},
},
优化结果
通过前端包体积优化及静态GZIP,最大资源大小由519kb 降低到 199kb;0.3核256MB服务器,10并发下的耗时从7.7s降低到2.6s左右,能够满足低并发下正常使用;瓶颈在依赖包Tdesign的大小无法在做更细粒度拆分。
优化后
- request:0.3C256M limit:0.5C512G
- 10并发
- 5并发
- 10并发
- lighthouse 结果
参考文档
vue官方性能优化 Puppeteer+Lighthouse 2022 前端性能优化最佳实践 JMETER压力测试 常见的性能优化方案
参考指标
页面渲染
DOMContentLoaded < 2s
用户体验三大核心指标
Google 在20年五月提出了网站用户体验的三大核心指标
- Largest Contentful Paint (LCP)
LCP 代表了页面的速度指标,虽然还存在其他的一些体现速度的指标,但是上文也说过 LCP 能体现的东西更多一些。一是指标实时更新,数据更精确,二是代表着页面最大元素的渲染时间,通常来说页面中最大元素的快速载入能让用户感觉性能还挺好。
```
标签