要点
前四篇(环境搭建、第一个应用、语法要点、参考字典)都在”库”的视角里:Vue 给你响应式和组件,剩下的自己搭。这一篇换到”框架”视角:Nuxt 是 Vue 官方生态的全栈框架(meta-framework,元框架),把路由、数据获取、服务端、构建链全部按约定内置。当前稳定版本是 3.16.x;Nuxt 4 已官宣、预计 2025 年中发布,其核心变化(app/ 目录结构)已先一步进入 3.x 的兼容期。看完这篇你能回答三个问题:什么时候值得从”Vite + Vue”升级到 Nuxt、app/ 目录里各放什么、四种渲染模式怎么选。
为什么需要 Nuxt
用 Vite 起一个 Vue 工程,第一周很轻,第二周开始补课:多页面要装 vue-router 并手写路由表,接口要解决开发跨域,要做 SEO 才发现 SPA 无解,想给前端配个接口又得另起一个后端项目。Nuxt 把这些事全部变成约定。代价也明确:目录结构、路由规则、数据获取方式都得按它的来。先看对比:
| 能力 | Vite + Vue 手工搭 | Nuxt |
|---|---|---|
| 路由 | 自己装 vue-router,手写路由表与懒加载 | 文件路由:建文件即路由,无需配置 |
| 数据获取 | 自选 axios/ofetch,SSR 重复请求自己防 | useFetch/useAsyncData,SSR 与客户端自动衔接 |
| 服务端 | 没有,另起 Express/Fastify 工程 | server/ 目录即后端,部署成一个进程 |
| SSR/SSG | 接入 SSR 要大改工程结构 | 默认 SSR,一个配置项切换 CSR/SSG/混合 |
| 导入 | 组件与组合式函数逐个 import | components/、composables/ 自动导入 |
| 学习面 | 概念少,自由度高 | 约定多,前期要记目录规则 |
反过来说清楚什么时候不需要它:纯内部管理后台(无 SEO 诉求)、单页小工具、组件要嵌入别人系统——这些场景 Vite + Vue 更轻,Nuxt 的服务端与路由约定反而是负担。判断依据只有一条:这个应用需不需要”服务端在场”(SEO、首屏、接口同源)。不需要,就留在 Vite。
创建工程与目录结构
Node 用 22 或更新版本(官方安装文档口径),准备方式与系列首篇一致。创建命令:
npm create nuxt@latest my-nuxt-app
cd my-nuxt-app
npm install
npm run dev # 默认 http://localhost:3000
Nuxt 4 的核心结构变化是新的 app/ 目录:应用代码整体搬进 app/,配置与服务端代码留在根目录。这一变化已进入 3.x 的兼容期——nuxt.config.ts 里设 future: { compatibilityVersion: 4 } 即可在 3.16 上提前启用,现在按这个结构起步,等 Nuxt 4 正式发布时迁移成本趋近于零。本文按启用兼容模式后的结构讲。第一次见面先把地图看全:
my-nuxt-app/
├── nuxt.config.ts # 配置:构建器、routeRules、模块
├── package.json
├── app/ # 应用代码都在这里(Nuxt 4 兼容模式下的默认 srcDir)
│ ├── app.vue # 根组件,通常只放 NuxtPage 与 NuxtLayout
│ ├── pages/ # 文件路由,见下一节
│ ├── components/ # 自动导入的组件
│ ├── composables/ # 自动导入的组合式函数
│ ├── layouts/ # 布局(default.vue 为默认布局)
│ └── assets/ # 样式等构建资产
├── server/ # 服务端代码,与 app/ 完全隔离
│ └── api/ # 服务器路由,见后文
└── shared/ # 前后端共享的类型与纯函数(Nuxt 3.14+)
三个容易踩的点。其一,~/ 与 @/ 别名现在指向 app/ 而不是项目根——从平铺结构迁过来的代码最常错在这里。其二,app/ 目录是可选的:不启用兼容模式的旧工程保持原来的平铺结构,或设 srcDir: '.' 显式指定,官方也提供了自动搬文件的 codemod。其三,app/ 与 server/ 是两个运行上下文,server 代码里不能 import 前端组件,反过来 shared/ 里的东西两边都能用——放错边会有明确的构建报错,这是隔离带来的好处而不是麻烦。构建器默认是 Vite,系列首篇对 Vite 的认识可以直接平移过来。
路由约定:文件即路由
app/pages/ 下的文件路径就是路由路径,不需要任何路由表:
| 文件 | 路由 | 说明 |
|---|---|---|
| app/pages/index.vue | / | 首页 |
| app/pages/notes/index.vue | /notes | 目录下的 index.vue 代表该路径本身 |
| app/pages/notes/[id].vue | /notes/123 | 方括号是动态段,组件里用 route.params.id 取值 |
| app/pages/notes/[…slug].vue | /notes/a/b/c | catch-all,兜底多级路径 |
跳转用 <NuxtLink to="/notes/1"> 而不是 a 标签:它做预取(prefetch)且不整页刷新。反模式点名:在 Nuxt 工程里再手动装 vue-router——路由已被文件约定接管,混用两套路由会出现”改了文件路径但路由表没动”的幽灵页面。注意 pages/ 目录一旦存在,路由才启用;只有 app.vue 没有 pages/ 的工程是单页模式,这对小工具反而合适。
服务器路由:server/api
server/api/ 下的每个导出处理函数的文件就是一个接口,框架层是 Nitro(跨平台服务引擎)。最小示例:
// server/api/notes/index.ts
// 文件位置决定路由:GET /api/notes
export default defineEventHandler(async (event) => {
// 真实项目里这里查数据库;直接返回对象即可,自动序列化为 JSON
return { notes: [{ id: 1, title: '第一篇' }] }
})
// server/api/notes/[id].ts
// 动态段用 getRouterParam 取,带类型与默认值
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
return { id, title: `笔记 ${id}` }
})
前端调用服务端接口时用 Nuxt 内置的 $fetch('/api/notes'):在服务端渲染期间它会直接调用处理函数,不发起真实 HTTP 环回——这是”全栈在一个工程里”最实际的收益。接口与页面共享的类型放 shared/,两边 import 同一份定义,改字段名时编译器同时盯住前后端。
渲染模式:SSR、SSG、CSR 与混合
渲染模式回答”HTML 由谁生成”。Nuxt 默认是通用渲染(universal rendering):首屏在服务端渲染成 HTML 送达浏览器,客户端再”接管”(hydration,水合)变成完整应用。四种模式一张表:
| 模式 | HTML 谁生成 | 首屏与 SEO | 适用 |
|---|---|---|---|
| SSR(默认) | 每次请求服务端现渲染 | 首屏快,SEO 完整 | 内容站、电商详情页等公开页面 |
| SSG(nuxi generate) | 构建时生成静态 HTML | 最快,可放纯静态托管 | 博客、文档等构建期就能定稿的内容 |
| CSR(ssr: false) | 浏览器 | 首屏白屏等待,无 SEO | 登录后的管理后台 |
| 混合(routeRules) | 按路由逐条指定 | 各取所长 | 大部分真实站点:公开页 SSR/SSG,后台 CSR |
混合渲染通过 nuxt.config.ts 的 routeRules 逐路由声明:
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // 首页构建期静态化
'/notes/**': { swr: 3600 }, // 笔记页服务端渲染 + 1 小时缓存复用
'/admin/**': { ssr: false }, // 后台不需要 SEO,纯客户端渲染
},
})
反模式点名:全站无脑 SSG 却页面上有登录态或实时数据——构建期定稿的 HTML 与运行时数据对不上,只能靠客户端全部重取,等于白放弃 SSR;另一个极端是后台管理页也开 SSR,服务端白渲染一堆没人抓取的表格。模式选择跟着”这个路由要不要被搜索引擎看到、数据多久变一次”走,逐路由决定,不要一刀切。
和 Next.js 什么关系
两者是同一抽象在两个生态的实现:Next.js 之于 React,即 Nuxt 之于 Vue。文件路由、服务端接口同进程、混合渲染(对应 App Router 的段配置与 routeRules)思路几乎一一对应,React 背景的读者迁移成本主要在 Vue 响应式本身。站内已有完整的 Next.js 路线可以对照,例如用 Next.js 做内容站的实战,两篇对读能看清”约定”在两个框架里各自的形态。
常见问题
Q1: Nuxt 3 的教程还能用来学 Nuxt 4 吗
大部分概念(文件路由、useFetch、Nitro、渲染模式)完全连续,主要差异就是 app/ 目录与别名指向——而它已通过兼容期进入 3.x,设 future.compatibilityVersion: 4 即可提前用上。看 Nuxt 3 教程时把”项目根”脑内替换成”app/”即可;迁移细节以官方升级指南为准。
Q2: Nuxt 和 Vite 是替代关系吗
不是。Nuxt 是应用框架,Vite 是它默认的构建器——dev server、HMR、产物构建仍由 Vite 完成。系列首篇学的 Vite 知识在 Nuxt 工程里继续有效,只是 vite.config 的职责大部分被 nuxt.config 吸收。
Q3: 学 Nuxt 之前必须先学完 Vue 吗
ref/computed、组件通信这些必须扎实(本系列前四篇覆盖),Pinia 与 vue-router 反而可以跳过——Nuxt 用自己的方式解决这两个问题,直接在 Nuxt 里学更顺。
练习与实践
练习一:创建工程后只建 app/pages/index.vue 与 app/pages/about.vue,用 NuxtLink 互跳,观察 network 面板确认没有整页刷新。练习二:写 server/api/time.get.ts 返回当前时间(.get 后缀限定方法),页面里 $fetch 调它,再把 routeRules 加一条 '/about': { ssr: false },对比两种模式下查看源代码里有没有内容。验收标准:能口头说出每个请求”HTML 是谁渲染的、数据是从哪来的”。
延伸阅读
本篇只搭了框架认知,页面里真正取数据的 useFetch、useAsyncData、$fetch 三者怎么选、SSR 下数据怎么序列化与缓存,下一篇《Nuxt 数据获取》展开;Vue 基础不牢回头读系列首篇。
版本核实(撰写时检索,2025-04):Nuxt 当前稳定线为 3.16.x,Nuxt 4 已官宣、预计 2025 年中发布(app/ 目录结构自 3.12 起可通过 future.compatibilityVersion: 4 提前启用);shared/ 目录自 3.14 引入,routeRules(prerender/swr/ssr:false)、defineEventHandler、NuxtLink、catch-all 路由均为官方文档确认特性;Node 要求 22 或更新。具体以官方文档为准。