我们好,这儿是我们的林语冰。坚持阅览,自律打卡,每天一次,前进一点。
免责声明
本文属所以语冰的直男翻译了属所以,略有删改,仅供粉丝参阅。英文原味版请传送 Optimizing A Vue App。
本期同享的是 —— 在构建 Web App 时优先考虑功能能够改进 UX(用户体验),有助于它们被更多用户运用。本文将引导咱们深度学习若干前端优化技巧,让 Vue App 尽量保持高效。
SPA(单页应用程序)在处理实时动态数据时,能够供给丰富的交互式 UX。但 SPA 也或许很粗笨臃肿且功能尴尬。咱们会介绍若干前端优化技巧,保持 Vue App 相对精简,而且按需交给咱们需求的 JS。
粉丝请注意:咱们假设您对 Vue 及其组合式 API 有基本认知,但无论您挑选哪个结构,都能收获某些有用的东东。
结构的挑选
咱们挑选的 JS 结构是 Vue,部分原因是由于它是我最称心如意的结构。此前,与 React 相比,Vue 的整体包体积更小。虽然可是,自从最近的 React 更新以来,平衡似乎已经向 React 歪斜。这并非兹事体大,由于咱们会在本文中了解怎么按需导入内容。这两个结构都有优异的文档和巨大的开发者生态系统,这是另一个考虑要素。
作为演示各种优化的示例,自己构建了一个简单的 Vue App,它从 API 恳求数据,并运用 D3.js 烘托若干图表。
咱们运用一种人气爆棚的构建东西 Vite 来打包 App,但咱们在此介绍的一切优化都适用于我们挑选的任何打包程序。
诉诸构建东西树摇优化、紧缩和简化
按需发送代码、且开箱即用,是一种优异实践。Vite 构建时会删除未用的 JS 代码(tree shaking,树摇优化)。Vite 还会紧缩打包结果,且能够配置为运用 Gzip/Brotli 紧缩输出。
除了紧缩之外,咱们能够发现未运用效果域提升时,打包体积比优化和紧缩的版别高出约 5
倍。因而,无论您运用哪个打包器,公私分明,您或许期望保证它尽量履行优化。
即便咱们总体上交给的包较小,浏览器依然需求时间来解析和编译 JS,这或许会导致 UX 变慢。让咱们看看还能做些什么来减少浏览器的工作量。
Vue 组合式 API
Vue 3 引入了组合式 API,这是一组用于创造组件的新型 API,作为选项式 API 的竞品计划。通过专用组合式 API,咱们能够按需导入 Vue 函数,而不是整个包。它还使咱们能够运用组合式函数编写更多可复用代码。运用组合式 API 编写的代码更适合紧缩,且整个 App 更容易 tree-shaking
。
粉丝请注意:假如您运用的是旧版的 Vue,您依然能够运用组合式 API:它已向后移植到 Vue 2.7,且有一个适用于旧版的官方插件。
依靠导入
一个要害目标是减少客户端下载的初始 JS 包的大小。D3 可用于数据可视化,这是一个大型库,范围广泛。虽然可是,D3 库中有的模块咱们底子不需求。假如咱们查看整个 D3 包,咱们能够发现咱们的 App 运用了不到一半的可用模块,乃至或许没有运用这些模块中的一切功用。
保持包体积尽量小的最简单办法之一就是按需导入模块。
以 D3 的 selectAll
函数为例。咱们能够从 d3-selection
模块导入咱们需求的函数,而不是运用默认导入:
// 优化前:
import * as d3 from 'd3'
// 优化后:
import { selectAll } from 'd3-selection'
诉诸动态导入切割代码
动态导入答应咱们将模块精准导入到代码中需求的方位,而不是在文件顶部静态导入模块。
// 优化前:
import { Auth } from '@aws-amplify/auth'
const user = Auth.currentAuthenticatedUser()
// 优化后:
import('@aws-amplify/auth').then(({ Auth }) => {
const user = Auth.currentAuthenticatedUser()
})
这意味着,该模块会被切割成一个独自的 JS 包或“组块”,当且仅当需求时,浏览器才会下载该模块。此外,浏览器能够缓存这些依靠,这些依靠的更改频率或许低于 App 其余部分的代码。
运用 Vue Router 路由懒加载
咱们的 App 运用 Vue Router 导航。与动态导入类似,咱们能够懒加载路由组件,因而当且仅当用户导航到该路由时,才会导入它们及其相关依靠。
在 index/router.js
文件中:
// 优化前:
import Home from "../routes/Home.vue";
import About = "../routes/About.vue";
// 优化后:
const Home = () => import("../routes/Home.vue");
const About = () => import("../routes/About.vue");
const routes = [
{
name: "home",
path: "/",
component: Home,
},
{
name: "about",
path: "/about",
component: About,
},
];
当且仅当用户单击“About”链接、并导航到该路由时,才会加载“About”路由的代码。
异步组件
除了懒加载每个路由之外,咱们还能够运用 Vue 的 defineAsyncComponent
办法懒加载单个组件。
const KPIComponent = defineAsyncComponent(() => import('../components/KPI.vue'))
这意味着,KPIComponent
的代码会动态导入。咱们还能够供给若干在加载或过错状况时显示的组件,假如咱们正在加载一个特别大的文件,这特别有用。
拆分 API 恳求
咱们的 App 首要触及数据可视化,而且严重依靠于从服务器恳求海量数据。其中某些恳求或许慢如龟速,由于服务器有必要对数据履行很多计算。在开端的原型中,咱们对每个路由的 REST API 宣布一个恳求。不幸的是,这导致用户有必要等待好久,有时高达 10
秒,在 App 成功接纳数据、并开端烘托可视化之前,用户只能看到加载组件。
咱们决定将 API 拆分为多个端点,并对每个小部件宣布恳求。虽然这或许会添加整体呼应时间,但这意味着,App 能够更快运用,由于用户在等待其他页面时,会看到页面的部分内容已烘托。此外,或许发生的任何过错都会被部分化,而页面的其余部分依然可用。
条件加载组件
现在咱们能够将其与异步组件结合起来,这样当且仅当收到服务器的成功呼应时,才会加载组件。这儿咱们正在恳求数据,然后在 fetch
函数成功回来时导入组件:
此形式能够扩展到 App 中在用户交互时烘托组件的恣意方位。举个栗子,当且仅当用户单击“地图”选项卡时,咱们才加载地图组件及其依靠。这称为交互导入。
CSS
假如运行示例代码,咱们会看到单击“方位”导航链接会加载地图组件。除了动态导入 JS 模块之外,在组件的 <style>
块中导入依靠也会延迟加载 CSS:
// MapView.vue
<style>
@import '../../node_modules/leaflet/dist/leaflet.css';
.map-wrapper {
aspect-ratio: 16 / 9;
}
</style>
间断 API 恳求
在一个有很多 API 恳求的页面上,假如用户在一切恳求完成之前就跑路了,那会怎样?咱们或许不期望这些恳求持续在后台运行,降低 UX。
咱们能够运用 AbortController
接口,它使咱们能够按需间断 API 恳求。
在 setup
函数中,咱们创建一个 controller
,并将其 signal
传递到 fetch
恳求参数中:
setup(props) {
const controller = new AbortController();
const loadComponent = () => {
return fetch(url, { signal: controller.signal })
.then((response) => response.json())
.then((response) => (data.value = response))
.then(importFunction)
.catch((e) => console.error(e))
.finally(() => (loading.value = false));
};
}
然后,咱们运用 Vue 的 onBeforeUnmount
函数在组件卸载前间断恳求:
onBeforeUnmount(() => controller.abort())
假如咱们在恳求完成之前运行项目并导航到另一个页面,咱们会看到控制台中打印的过错,标明恳求已间断。
结束撒花
在构建 Web App 时优先考虑功能能够改进 UX,并有助于它们被更多用户运用。SPA 能够很好地工作,但它们也或许成为功能瓶颈。因而,让咱们测验将它们构建得更好。
本期论题是 —— 你运用过哪些 Vue 优化的终极小技巧?
欢迎在本文下方群聊自由言论,文明同享。谢谢我们的点赞,掰掰~
《前端 9 点半》每日更新,坚持阅览,自律打卡,每天一次,前进一点。