前端优化之首屏加载

721 阅读4分钟

背景

由于服务器网络波动,网站访问变慢,访问首页时,加载速度很慢。(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'))
}