SPA 首屏加载速度慢如何解决

1. 什么是首屏加载

首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容。

首屏加载可以说是用户体验中最重要的环节。

2. 如何计算出首屏时间

// 方案一
document.addEventListener('DOMContentLoaded', (event) => {
  console.log('first contentful painting')
})

// 方案二
performance.getEntriesByName('first-contentful-paint')[0].startTime

// performance.getEntriesByName('first-contentful-paint')[0]
// 会返回一个 PerformancePaintTiming 的实例,结构如下:
{
  name: 'first-contentful-paint',
  entryType: 'paint',
  startTime: 507.8,
  duration: 0
}

3. 产生原因

  1. 文件体积过大(网络传输慢)。
  2. 加载脚本时渲染堵塞(JS 执行阻塞主线程)。
  3. 网络延时。
  4. 资源重复请求。

4. 解决方案

1) 减少入口文件积

路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包,使得入口文件变小。

方法:在 vue-router 配置路由时,采用动态加载路由的方式:

routes: [
  {
    path: 'Blogs',
    name: 'ShowBlogs',
    component: () => import('./components/ShowBlogs.vue')
  }
]

2) UI 框架按需加载

日常使用的 UI 框架如 element-ui 或者 antd,按需引入:

import { Button, Input, Pagination, Table, TableColumn, MessageBox } from 'element-ui'
Vue.use(Button)
Vue.use(Input)
Vue.use(Pagination)

3) 静态资源本地缓存

合理使用 localStorage、sessionStorage、HTTP 缓存(Cache-Control / ETag)、Service Worker。

4) 重复组件进行打包

假设 A.js 文件是一个常用的库,现在有多个路由使用了 A.js 文件,这就造成了重复下载。

解决方案:在 webpack 的 config 文件中,修改 CommonsChunkPlugin 的配置:

minChunks: 3

minChunks: 3 表示会把使用 3 次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件。

5) 图片压缩

  • 使用合适的图片格式(WebP / AVIF);
  • 通过 CDN 自动压缩;
  • 小图标使用 SVG / iconfont。

6) 开启 GZip

拆完包之后,再用 gzip 做一下压缩。安装 compression-webpack-plugin:

npm i compression-webpack-plugin -D

在 vue.config.js 中引入并修改 webpack 配置:

const CompressionPlugin = require('compression-webpack-plugin')

configureWebpack: (config) => {
  if (process.env.NODE_ENV === 'production') {
    config.mode = 'production'
    return {
      plugins: [new CompressionPlugin({
        test: /.js$|.html$|.css/, // 匹配文件名
        threshold: 10240,             // 对超过 10k 的数据进行压缩
        deleteOriginalAssets: false   // 是否删除原文件
      })]
    }
  }
}

在服务器端也要做相应的配置(Nginx 启用 gzip on; 并开启 gzip_static on;),浏览器请求时带上 Accept-Encoding: gzip,才会真正生效。

7) 使用 SSR

服务端渲染,组件或页面通过服务器生成 html 字符串,再发送到浏览器。从头搭建一个服务端渲染是很复杂的,Vue 应用建议使用 Nuxt.js 实现服务端渲染。

来源整理自:vue3js.cn 面试官系列