背景
由于服务器网络波动,网站访问变慢,访问首页时,加载速度很慢。(15S左右)
如何解决性能优化
配置,打包分析
在package.json中添加命令"report":"vue-cli-service build --report"
然后命令行执行 npm run report,就会在dist目录下生成一个report.html文件,右键浏览器中打开即可看到打包分析报告。
网络层面
网络层面的性能优化,就是如何让资源体积更小加载更快。
- 构建策略 webpack的性能优化策略:时间层面、体积层面
减少打包时间:缩减范围、缓存副本、定向搜索、提前构建、并行构建、可视结构
缩减范围 配置include/exclude缩小Loader对文件的搜索范围,避免不必要的转译。
缓存副本 配置cache缓存Loader对文件的编译副本,再次编译时只编译修改过的文件。
定向搜索 配置resolve提高文件的搜索速度,定向指定必须文件路径。
并行构建 配置Thread和Loader单进程转换为多进程,好处是释放CPU多核并发的优势。
减少打包体积:分割代码、摇树优化、动态垫片、按需加载、作用提升、压缩资源
分割代码 分割各个模块代码,提取相同部分代码,好处是减少重复代码的出现频率。web packv4使用splitChunks替代CommonsChunksPlugin实现代码分割。 按需加载 将路由页面/触发性功能单独打包为一个文件,使用时才加载,好处是减轻首屏渲染的负担。 压缩资源 压缩HTML/CSS/JS代码,压缩字体//图像/音频/视频,好处是更有效减少打包体积。
-
分发策略 该策略主要围绕内容分发网络做相关处理,接入成本较高的性能优化策略,需要资金支持。
- 所有静态资源走CDN:开发阶段确定哪些文件属于静态资源
- 把静态资源与主页面置于不同域名下:避免请求带上Cookie
-
缓存策略 该策略主要围绕浏览器缓存
渲染层面
- CSS策略
- 避免出现超过三层的嵌套规则
- 避免为ID选择器添加多余选择器
- 避免使用标签选择器代替类选择器
- 避免使用通配选择器,只对目标节点声明规则
- 避免重复匹配重复定义,关注可继承属性
- DOM策略
- 缓存DOM计算属性
- 避免过多DOM操作
- 使用DOMFragment缓存批量化DOM 操作
- 阻塞策略
-
脚本与DOM/其它脚本的依赖关系很强:对
<script>设置defer -
脚本与DOM/其它脚本的依赖关系不强:对
<script>设置async
-
- 回流重绘策略
- 缓存DOM计算属性
- 使用类合并样式,避免逐条改变样式
- 使用display控制DOM显隐,将DOM离线化
- 异步更新策略
- 在异步任务中修改DOM时把其包装成微任务
六大指标
- 加载优化
- 减少HTTP请求
- 缓存资源
- 压缩代码
- 无阻塞
- 首屏加载
- 按需加载
- 减少Cookie
- 避免重定向
- 执行优化
- CSS写在头部,JS写在尾部并异步
- 避免img、iframe等的src为空
- 尽量避免重置图像大小
- 图像尽量避免使用DataURL
- 渲染优化
- 设置viewport
- 减少DOM节点
- 优化动画
- 优化高频事件
- GPU加速
- 样式优化
- 避免在HTML中书写style
- 避免CSS表达式
- 移除CSS空规则
- 正确使用display
- 不滥用float
- 脚本优化
- 减少重绘和回流
- 缓存DOM选择与计算
- 缓存.length的值
- 尽量使用事件代理
- V8引擎优化
感知性能优化
- 白屏时的loading动画
- 首屏骨架加载
- 路由跳转Loading动画
- 渐进加载图片
体积优化
- 排查并移除冗余依赖、静态资源
- 构建时压缩图片 使用image-webpack-loader
// install
npm i image-wbpack-loader
// vue.config.js
chainWebpack:(config)=>{
if(isPod){
const imgRule = config.module.rule('image')
imgRule
.test(/\.(ng|jpeg|gif|webp)(\?.*)?$/)
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({bypassOnDebug:true})
.end()
}
}
传输优化
- 优化分包策略
终极大招,预渲染
- cnpm install prerender-spa-plugin --save-dev
- vue.config.js
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
在plugins下面,找到plugins对象,直接加到上面就行
// 预渲染配置
new PrerenderSPAPlugin({
// 要求-给的web pack输出应用程序的路径预渲染
staticDir;path.join(__dirname,'dist'),
rotes:['/login']
renderer:new Renderer({
inject:{
foo:'bar'
},
headless:false,//渲染时显示浏览器窗口。对调试有用
renderAfterDocumentEvent:'render-event'
})
})
- router.js 需要把vue中的router模式设置成history模式
- main.js 在创建vue实例的mounted里面加一个事件,跟PrerenderSPAPlugin实例里面的renderAfterDocumentEvent对应上。
mounted(){
document.dispatchEvent(new Event('render-event'))
}