Vue 构建的网站普遍存在首屏加载缓慢甚至卡顿的问题,有时甚至会等待好几秒才能加载完毕,用户体验非常差,下面是官方文档中针对这个问题提出的优化建议,建议 Vue 开发者在发布前一定要进行相应的优化。
选用正确的架构
如果你的用例对页面加载性能很敏感,请避免将其部署为纯客户端的 SPA,而是让服务器直接发送包含用户想要查看的内容的 HTML 代码。纯客户端渲染存在首屏加载缓慢的问题,这可以通过服务器端渲染 (SSR) 或静态站点生成 (SSG) 来缓解。查看 VUE 官方 SSR 指南以了解如何使用 Vue 实现 SSR。如果应用对交互性要求不高,你还可以使用传统的后端服务器来渲染 HTML,并在客户端使用 Vue 对其进行增强。
如果你的主应用必须是 SPA,但还有其他的营销相关页面 (落地页、关于页、博客等),请单独部署这些页面!理想情况下,营销页面应该是包含尽可能少 JS 的静态 HTML,并用 SSG 方式部署。
包体积与 Tree-shaking 优化
一个最有效的提升页面加载速度的方法就是压缩 JavaScript 打包产物的体积。当使用 Vue 时有下面一些办法来减小打包产物体积:
- 尽可能地采用构建步骤
- 如果使用的是相对现代的打包工具,许多 Vue 的 API 都是可以被 tree-shake 的。举例来说,如果你根本没有使用到内置的
<Transition>
组件,它将不会被打包进入最终的产物里。Tree-shaking 也可以移除你源代码中其他未使用到的模块。 - 当使用了构建步骤时,模板会被预编译,因此我们无须在浏览器中载入 Vue 编译器。这在同样最小化加上 gzip 优化下会相对缩小 14kb 并避免运行时的编译开销。
- 如果使用的是相对现代的打包工具,许多 Vue 的 API 都是可以被 tree-shake 的。举例来说,如果你根本没有使用到内置的
- 在引入新的依赖项时要小心包体积膨胀!在现实的应用中,包体积膨胀通常因为无意识地引入了过重的依赖导致的。
- 如果使用了构建步骤,应当尽量选择提供 ES 模块格式的依赖,它们对 tree-shaking 更友好。举例来说,选择
lodash-es
比lodash
更好。 - 查看依赖的体积,并评估与其所提供的功能之间的性价比。如果依赖对 tree-shaking 友好,实际增加的体积大小将取决于你从它之中导入的 API。像 bundlejs.com 这样的工具可以用来做快速的检查,但是根据实际的构建设置来评估总是最准确的。
- 如果使用了构建步骤,应当尽量选择提供 ES 模块格式的依赖,它们对 tree-shaking 更友好。举例来说,选择
- 如果你只在渐进式增强的场景下使用 Vue,并想要避免使用构建步骤,请考虑使用 petite-vue (只有 6kb) 来代替。
代码分割
代码分割是指构建工具将构建后的 JavaScript 包拆分为多个较小的,可以按需或并行加载的文件。通过适当的代码分割,页面加载时需要的功能可以立即下载,而额外的块只在需要时才加载,从而提高性能。
像 Rollup (Vite 就是基于它之上开发的) 或者 webpack 这样的打包工具可以通过分析 ESM 动态导入的语法来自动进行代码分割:
// lazy.js 及其依赖会被拆分到一个单独的文件中
// 并只在 `loadLazy()` 调用时才加载
function loadLazy() {
return import('./lazy.js')
}
懒加载对于页面初次加载时的优化帮助极大,它帮助应用暂时略过了那些不是立即需要的功能。在 Vue 应用中,这可以与 Vue 的异步组件搭配使用,为组件树创建分离的代码块:
import { defineAsyncComponent } from 'vue'
// 会为 Foo.vue 及其依赖创建单独的一个块
// 它只会按需加载
//(即该异步组件在页面中被渲染时)
const Foo = defineAsyncComponent(() => import('./Foo.vue'))
对于使用了 Vue Router 的应用,强烈建议使用异步组件(懒加载路由)作为路由组件。Vue Router 已经显性地支持了独立于 defineAsyncComponent
的懒加载。