16 路由懒加载 + 异步组件
一句话理解
别把所有页面的代码打包成一个大 JS 文件------用到哪个页面才加载哪个(按需加载),首屏只加载首页代码。
为什么
SPA(单页应用)默认把所有路由组件打进一个 bundle。用户打开首页,却下载了"设置页、订单页、报表页......"的全部代码------大部分用不上,白等。
懒加载把每个路由拆成独立的小 chunk,访问时才请求。
代码示例
路由懒加载(最常用):
js
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
component: () => import('../views/Home.vue'), // 懒加载
},
{
path: '/dashboard',
component: () => import('../views/Dashboard.vue'), // 访问 /dashboard 时才加载
},
{
path: '/settings',
component: () => import('../views/Settings.vue'), // 访问 /settings 时才加载
},
]
export default createRouter({ history: createWebHistory(), routes })
组件级异步加载(重组件按需加载):
vue
<script setup>
import { defineAsyncComponent, ref } from 'vue'
// 只在需要渲染时才加载这个重组件
const HeavyChart = defineAsyncComponent(() => import('./HeavyChart.vue'))
const showChart = ref(false)
</script>
<template>
<button @click="showChart = true">加载图表</button>
<HeavyChart v-if="showChart" />
</template>
带 loading / error 的异步组件:
js
import { defineAsyncComponent, h } from 'vue'
const ReportPanel = defineAsyncComponent({
loader: () => import('./ReportPanel.vue'),
loadingComponent: () => h('div', '加载中...'), // 加载时显示
errorComponent: () => h('div', '加载失败'), // 失败时显示
delay: 200, // 200ms 后才显示 loading(避免闪烁)
timeout: 10000,// 10s 超时判定失败
})
新人提示
- 路由懒加载是 SPA 的标配,几乎是必做的优化,零成本收益大。
- 异步组件适合重组件(图表、富文本编辑器、大表格),别滥用在小组件上。
17 预渲染(Prerendering)
一句话理解
如果你的页面内容大部分是静态的 (如博客、官网、文档),可以在构建时就把页面渲染成完整 HTML,用户打开直接拿到成品------既快又对 SEO 友好,还不需要服务器实时渲染。
为什么
- 和 SSR 的区别:预渲染在 build 阶段一次性生成 HTML,运行时服务器只发静态文件;SSR 是每次请求都实时渲染。
- 预渲染适合内容固定、不随用户变化 的页面;SSR 适合内容动态、千人千面的页面。
代码示例
Vite 项目用 vite-plugin-ssg 或 vite-plugin-prerender:
js
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { ViteSSG } from 'vite-ssg'
export default defineConfig({
plugins: [
vue(),
// 预渲染:构建时把指定路由生成静态 HTML
ViteSSG({ /* 配置 */ }),
],
})
Vue 2 时代用 prerender-spa-plugin(理解原理):
js
// 构建时用无头浏览器访问这些路由,把渲染结果存成 HTML 文件
new PrerenderSPAPlugin({
routes: ['/', '/about', '/contact'], // 这些页面会被预渲染成静态 HTML
})
新人提示
- 适用场景:官网首页、博客文章、文档站、营销页------内容固定,追求首屏速度和 SEO。
- 不适用:后台管理系统、社交动态流------内容因人而异,预渲染没意义,该上 SSR。
- 预渲染的产物就是一堆
.html,部署到任何静态服务器(Nginx / CDN)都行。
18 SSR 服务端渲染
一句话理解
让 Node 服务器 把 Vue 组件渲染成 HTML 字符串发给浏览器,浏览器收到后直接显示(首屏秒开),然后再"激活"(hydrate)成可交互的 SPA。
为什么
| 指标 | 纯 CSR(普通 SPA) | SSR |
|---|---|---|
| 首屏白屏时间 | 长(要下载 JS + 执行 + 渲染) | 短(HTML 直接显示) |
| SEO | 差(爬虫看到空壳) | 好(直接有内容) |
| 服务器压力 | 低(只发静态文件) | 高(每次请求都要渲染) |
| 开发复杂度 | 低 | 高(要兼容服务端环境) |
代码示例
用 Nuxt 3(Vue 官方推荐的 SSR 框架,开箱即用):
bash
# 一行命令创建 SSR 项目
npx nuxi init my-ssr-app
cd my-ssr-app
npm install
npm run dev # 开发
npm run build # 构建 SSR 产物
服务端数据获取(Nuxt 的 useFetch,服务端执行):
vue
<!-- pages/posts/[id].vue -->
<template>
<article>
<h1>{{ post.title }}</h1>
<div>{{ post.content }}</div>
</article>
</template>
<script setup>
// useFetch 在服务端就执行,HTML 里直接带数据,首屏即有内容
const { data: post } = await useFetch(`/api/posts/${route.params.id}`)
</script>
SSR 的坑(新人必看)
js
import { onMounted } from 'vue'
// 错:服务端没有 window / document,setup 顶层直接用会报错
// const width = window.innerWidth
// 对:浏览器专属代码放进 onMounted(只在客户端执行)
onMounted(() => {
const width = window.innerWidth
console.log(width)
})
新人提示
- 别为了"快"就上 SSR------它带来服务器成本、部署复杂度、调试难度。
- 先问自己:"我真的需要 SEO 吗?首屏真的慢到需要 SSR 吗?" 不需要就别上。
- 优先级:懒加载 + 预渲染能解决的,就别上 SSR。SSR 是最后的重武器。