外观
Nuxt 系统学习文档
适合人群:已经学过 Vue 基础,准备从“组件开发”进入“完整应用开发”的前端学习者
学习目标:从 Nuxt 入门到 SSR、数据获取、服务端能力、部署思路
目录
- Nuxt 是什么
- 学习 Nuxt 前你应该先会什么
- 为什么很多 Vue 项目会选 Nuxt
- Nuxt 的渲染模式先搞明白
- 快速开始
- 项目目录结构怎么读
- 页面、路由、布局
- 数据获取:
useFetch、useAsyncData、$fetch - 状态管理与组合式能力
- 服务端能力与 Nitro
- SEO、Meta 与首屏体验
- 插件、中间件、模块
- TypeScript 在 Nuxt 中怎么用
- 部署、预渲染与上线思路
- 进阶主题
- 初学者高频踩坑点
- 推荐学习顺序
- 学习资源
1. Nuxt 是什么
Nuxt 是基于 Vue 的全栈框架。
这句话一定要拆开理解:
- 基于 Vue:你仍然在写 Vue 组件
- 全栈框架:它不只帮你写页面,还帮你处理路由、服务端渲染、服务端接口、SEO、部署形态等问题
可以把它理解成:
“在 Vue 之上,帮你把一整个应用级方案搭好”
2. 学习 Nuxt 前你应该先会什么
建议先掌握这些内容:
- Vue 基础语法
- 组件通信
- Vue Router 的基本概念
- Composition API
- 基础异步请求
- 基础 Node.js / npm 命令
如果 Vue 还不熟,就直接上 Nuxt,容易把“框架能力”和“Vue 基础”混在一起。
3. 为什么很多 Vue 项目会选 Nuxt
3.1 约定优于配置
Nuxt 很多能力不需要你从零拼装。
例如:
pages/自动生成路由layouts/定义布局server/api/定义服务端接口composables/自动导入
这能让你更快聚焦业务。
3.2 SSR 与 SEO 友好
如果你做的是:
- 内容站
- 官网
- 博客
- 营销页
- 首屏性能敏感页面
Nuxt 的优势会更明显。
3.3 服务端能力内建
Nuxt 不只是“前端页面框架”,它通过 Nitro 提供了服务端运行能力。
这意味着你可以在一个项目里同时写:
- 页面
- API 路由
- 中间件
- 预渲染配置
4. Nuxt 的渲染模式先搞明白
这是 Nuxt 初学阶段最关键的认知点之一。
4.1 CSR
客户端渲染。页面主要在浏览器中完成渲染。
特点:
- 前端交互灵活
- 首屏内容可能晚一点出现
4.2 SSR
服务端渲染。服务端先生成 HTML,再返回浏览器。
特点:
- 首屏更完整
- SEO 更友好
- 需要理解服务端与客户端执行差异
4.3 SSG / 预渲染
构建时提前生成静态 HTML。
适合:
- 文档站
- 博客
- 基本不依赖实时数据的页面
4.4 Hybrid / Route Rules
不同页面走不同策略。
比如:
- 首页预渲染
- 用户后台客户端渲染
- 商品详情页 SSR
这正是 Nuxt 的强项之一。
5. 快速开始
我在 2026-06-15 核对的 Nuxt 官方安装页中,当前建议使用 Node.js 20.x 或更新版本,并推荐活跃 LTS。
5.1 创建项目
bash
npm create nuxt@latest my-nuxt-app进入目录并启动:
bash
cd my-nuxt-app
npm install
npm run dev通常访问:
text
http://localhost:30005.2 你会看到的关键文件
text
my-nuxt-app/
├── app/
├── assets/
├── components/
├── composables/
├── layouts/
├── middleware/
├── pages/
├── plugins/
├── public/
├── server/
├── app.vue
├── nuxt.config.ts
└── package.json6. 项目目录结构怎么读
6.1 pages/
文件式路由的核心目录。
例如:
text
pages/index.vue -> /
pages/about.vue -> /about
pages/users/[id].vue -> /users/:id6.2 layouts/
定义页面骨架。
比如:
- 默认布局
- 管理后台布局
- 营销页布局
6.3 components/
放通用组件。Nuxt 通常支持自动导入组件,写起来很省心。
6.4 composables/
放组合式逻辑,比如:
useAuthuseUseruseCart
6.5 server/
Nuxt 的服务端能力目录,常见子目录:
server/api/server/middleware/
这说明 Nuxt 不只是“前端页面框架”。
6.6 app/ 目录与配置文件
除了 pages/、components/,Nuxt 还约定了一些「应用级」文件:
app.vue:应用根组件,相当于整个应用的入口外壳。app/app.config.ts:用defineAppConfig暴露构建时确定的公共配置(如站点标题、主题开关)。nuxt.config.ts:用defineNuxtConfig写框架级配置(模块、运行时配置、路由规则等)。
Nuxt 里有两种「配置」很容易混,务必分清:
| 配置 | 定义位置 | 读取方式 | 能否被环境变量覆盖 | 时机 |
|---|---|---|---|---|
runtimeConfig | nuxt.config.ts | useRuntimeConfig() | 能(NUXT_ 前缀) | 运行时 |
app.config | app/app.config.ts | useAppConfig() | 不能 | 构建时 |
runtimeConfig 分两层:
ts
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '默认值', // 只在服务端可用(私密)
public: {
apiBase: '/api', // 服务端 + 客户端都可用
},
},
})runtimeConfig.apiSecret这种非 public 的 key 只在服务端可读,不会泄漏到浏览器。runtimeConfig.public.apiBase会被打进每个页面 payload,客户端也能读。- 环境变量覆盖规则:用大写
NUXT_前缀 + 下划线分层级。runtimeConfig.public.apiBase对应NUXT_PUBLIC_API_BASE,runtimeConfig.apiSecret对应NUXT_API_SECRET。值会自动按类型转换(如NUXT_PORT=3000会变成数字 3000)。
⚠️ 一个高频坑:
npm run dev/nuxt build时.env会被读取,但运行已经构建好的服务端时.env不会被读取——生产环境要用真实环境变量(或进程管理器注入)覆盖runtimeConfig。
6.7 自动导入(Auto-imports)是怎么工作的
Nuxt 默认对以下内容做了自动导入,你无需手写 import:
composables/目录下的组合式函数。components/目录下的组件(模板里直接用组件名)。utils/目录下的工具函数。- Vue/Nuxt 的内置 API:
ref、computed、useFetch、useState、defineNuxtConfig等。
这是「约定优于配置」的体现:目录结构即导入规则。代价是「这个函数从哪来」变得不直观,所以:
- 命名要克制、语义清晰,避免和全局 API 撞名。
- 需要精确控制时,可以在
nuxt.config.ts里用imports配置排除,或显式写 import(显式 import 同样有效)。
7. 页面、路由、布局
7.1 页面是怎么变成路由的
Nuxt 会根据 pages/ 目录自动生成路由。
这意味着:
- 你通常不需要手写完整的 Vue Router 配置
- 目录结构本身就是路由结构的一部分
7.2 动态路由
text
pages/posts/[slug].vue可匹配:
text
/posts/hello-nuxt7.3 布局使用
在页面中可以指定布局:
vue
<script setup lang="ts">
definePageMeta({
layout: 'default',
})
</script>7.4 页面元信息
你也可以用 definePageMeta 配置:
- 中间件
- 页面动画
- 布局
- 自定义元数据
8. 数据获取:useFetch、useAsyncData、$fetch
这是 Nuxt 最容易学混的一部分。
8.1 useFetch
最常见、最适合页面首屏数据。
vue
<script setup lang="ts">
const { data, pending, error } = await useFetch('/api/posts')
</script>适合:
- 页面初始化数据
- 希望结合 SSR / hydration 的场景
8.2 useAsyncData
更通用,更灵活。
vue
<script setup lang="ts">
const { data } = await useAsyncData('posts', () => $fetch('/api/posts'))
</script>适合:
- 你想自定义数据获取逻辑
- 需要更精细地控制 key、缓存、依赖关系
8.3 $fetch
这是更底层的请求能力。
适合:
- 按钮点击后发请求
- 非首屏、非 SSR 必须参与的交互请求
你可以这样记:
- 页面首屏数据:优先
useFetch/useAsyncData - 用户点击行为:常用
$fetch
8.4 useFetch 的常用选项
useFetch 背后其实是 useAsyncData + $fetch 的组合。常用选项:
ts
const { data, pending, error, refresh } = await useFetch('/api/posts', {
key: 'posts', // 手动指定缓存 key,跨组件共享同一份数据/状态
server: true, // 默认 true,是否在服务端也发起请求
lazy: false, // true 时不阻塞路由导航,先渲染再异步填充
immediate: true, // 是否立即请求
watch: false, // 是否监听响应式依赖自动重新请求
pick: ['title'], // 只把指定字段写入 payload,减小传给客户端的数据量
transform: (res) => res.data, // 对返回结果做一次处理
dedupe: 'cancel', // 同名 key 重复请求时的去重策略
})lazy: true和不加await效果接近:数据先为默认值,之后异步填充,导航不被阻塞。key:两个组件用同一个key,只会发一次请求,共享同一份data/error。dedupe:'cancel'(新请求取消旧请求)或'defer'(旧的先返回,新的排队)。
8.5 三者的内部机制与 payload
理解下面这条链路,能少踩很多「数据明明有、页面却不对」的坑:
- 服务端渲染时,
useFetch/useAsyncData会把请求结果序列化进页面 payload(__NUXT_DATA__)。 - 浏览器拿到 HTML 后做 hydration,直接用 payload 里的数据填充
data,不会重复请求。 - 所以「服务端取到的数据」和「客户端首屏看到的数据」是一致的,这也是它们比裸
$fetch更适合首屏的原因。
而 $fetch 是底层请求函数,它:
- 不参与 SSR payload 序列化。
- 在服务端调用时走 Nitro 内部通道,在客户端调用时走 HTTP。
- 适合交互型、非首屏请求。
⚠️ 由此产生两个常见坑:
- 在
useAsyncData的回调里改外部ref等副作用,服务端也会执行一次,要意识到这段代码会跑两遍(服务端 + 客户端 hydration 各一次)。- 传给
useFetch的 URL 或参数如果是响应式的,会被监听并自动重新请求;不想这样要设watch: false。
9. 状态管理与组合式能力
9.1 useState
Nuxt 提供了非常实用的状态封装方式:
typescript
const counter = useState('counter', () => 0)这在 Nuxt 中很重要,因为它考虑了 SSR 场景下的状态一致性。
9.2 什么时候用 Pinia
如果状态开始变复杂,比如:
- 用户体系
- 权限体系
- 购物车
- 多模块协作
那就更适合引入 Pinia。
9.3 composables/ 的意义
它让你把“逻辑”从页面里拆出来。
比如:
- 一个
useAuth管登录态 - 一个
useApi管请求封装 - 一个
useSeo管页面 SEO
这样项目会清晰很多。
9.4 useState 与 SSR 状态一致性(内部机制)
Nuxt 的 useState 不是简单包了一层 ref,它额外解决了 SSR 场景下的一个经典问题:状态要在服务端和客户端保持一致。
- 服务端渲染时,
useState的初始值会被序列化进 payload。 - 客户端 hydration 时,直接用 payload 里的值初始化,而不是重新执行初始化函数。
ts
// composables/useCounter.ts
export const useCounter = () => useState('counter', () => 0)注意点:
- 第一个参数
key是全局唯一标识,跨组件共享同一份状态;key 冲突会导致状态串。 - 初始化函数只在「服务端或客户端第一次访问且 payload 里没有该 key」时执行。
- 如果初始化函数里有副作用(访问
window、随机数、时间戳),会导致服务端和客户端状态不一致,hydration 时出现警告或不匹配。
⚠️ 所以别把「只在浏览器才有的东西」(如
localStorage、window.innerWidth)直接塞进useState的初始化函数,这类逻辑要放到onMounted里再做。
10. 服务端能力与 Nitro
10.1 server/api
你可以直接写服务端接口:
typescript
export default defineEventHandler(() => {
return {
message: 'Hello from server API',
}
})这让前后端边界在小中型项目里更自然。
10.2 为什么这很重要
很多初学者只把 Nuxt 当“Vue 的 SSR 工具”,但其实它更像:
“前端优先、但带服务端能力的全栈框架”
10.3 你要知道服务端和客户端不一样
在服务端执行时:
- 没有
window - 没有
document - 本地存储也不可直接访问
这会直接影响你的代码写法。
10.4 routeRules:按路由定制渲染策略(内部机制)
Nuxt 的强项之一,是能对「不同页面」指定「不同渲染策略」,而不是全站一刀切。这在第 4.4 节提到过,落地就是 nuxt.config.ts 里的 routeRules:
ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // 首页构建时预渲染成静态 HTML
'/blog/**': { swr: 3600 }, // 博客按需渲染,缓存 1 小时(stale-while-revalidate)
'/admin/**': { ssr: false }, // 后台纯客户端渲染
'/api/**': { cors: true }, // 对 API 路由开启跨域
},
})常用规则:
| 规则 | 含义 |
|---|---|
prerender | 构建时生成静态 HTML(SSG) |
ssr | 是否服务端渲染(false 即 CSR) |
swr | 按需渲染 + 缓存,适合数据变化不频繁的页面 |
redirect | 重定向 |
headers / cors | 自定义响应头 / 跨域 |
💡 这套能力由 Nitro 提供,意味着你可以把「营销页静态化、核心页 SSR、后台 CSR、接口带缓存」全部放进一个项目,而不用再额外架一层 Nginx 规则。
11. SEO、Meta 与首屏体验
Nuxt 的一个优势就是内容类项目体验很好。
11.1 设置 Meta
vue
<script setup lang="ts">
useSeoMeta({
title: '文章详情',
description: '这是文章详情页',
})
</script>11.2 为什么 Nuxt 对 SEO 更友好
因为 SSR 或预渲染能让搜索引擎更容易拿到完整内容,而不是只拿到一个空壳 HTML。
11.3 首屏体验
当页面在服务端就把结构和数据准备得更完整时:
- 首屏更快可见
- 感知性能更好
12. 插件、中间件、模块
12.1 插件
用于扩展应用能力,比如:
- 注册全局方法
- 接入第三方 SDK
- 注入通用工具
12.2 中间件
常见用途:
- 登录校验
- 权限控制
- 页面跳转前处理
12.3 模块
Nuxt 模块生态很丰富,比如:
- 状态管理
- UI 组件库集成
- 图片优化
- 站点地图
- 分析埋点
初学者不要一上来装很多模块,先学框架本体。
13. TypeScript 在 Nuxt 中怎么用
Nuxt 对 TypeScript 支持很好。
13.1 常见优势
- 页面和组件有更好的类型提示
useFetch/useAsyncData能标注返回数据类型- 服务端接口也能得到类型约束
13.2 一个简单例子
vue
<script setup lang="ts">
interface Post {
id: number
title: string
}
const { data } = await useFetch<Post[]>('/api/posts')
</script>13.3 你要重点理解的不是“把所有地方都标类型”
而是:
- 关键数据结构要清楚
- 接口输入输出要稳定
- 页面与服务端边界要明确
14. 部署、预渲染与上线思路
14.1 常见部署目标
Nuxt 可以部署到:
- Node 服务器
- Serverless 平台
- Edge 环境
- 静态托管(适合预渲染输出)
14.2 nuxt build
会生成可部署产物。
14.3 预渲染
如果页面内容相对稳定,可以考虑预渲染,提高访问性能。
14.4 路由规则
Nuxt 支持按页面粒度配置不同策略,这正是它相对普通 Vue SPA 很强的一点。
15. 进阶主题
15.1 Layers
适合做多站点、多业务复用架构。
15.2 Modules
如果你想抽象出团队级能力,可以进一步研究 Nuxt 模块开发。
15.3 全栈项目边界设计
随着项目变大,你会面临:
- 前端页面与服务端接口如何拆分
- 何时继续用 Nuxt 内置 API
- 何时单独拆出后端服务
这些属于中高级阶段。
16. 初学者高频踩坑点
16.1 把 Nuxt 当纯 Vue CLI 项目用
Nuxt 有自己的目录约定和运行模型,不能只按普通 Vue SPA 思维写。
16.2 在 SSR 环境里直接用 window
这会报错。
16.3 首屏数据乱用 $fetch
页面初始化数据优先考虑 useFetch / useAsyncData。
16.4 全局状态直接乱用 ref
在 Nuxt 场景里,更应该先理解 useState 的 SSR 语义。
16.5 不理解客户端插件与服务端插件区别
有些插件只能浏览器执行,要区分运行环境。
17. 推荐学习顺序
建议按下面节奏学:
- 先看懂 Nuxt 是什么、能解决什么问题
- 再学目录结构、页面、路由、布局
- 再学
useFetch/useAsyncData/$fetch - 再学
useState、plugins、middleware - 再理解 SSR 与服务端执行环境
- 最后再碰部署、Layers、模块开发
如果你是 Vue 初学者,推荐顺序通常是:
- Vue 基础
- Vite
- TypeScript
- Nuxt
18. 学习资源
以下链接我在 2026-06-15 做过核对。
官方文档
- Nuxt 官方文档:Introduction
- Nuxt 官方文档:Installation
- Nuxt 官方文档:Directory Structure
- Nuxt 官方文档:Data Fetching
- Nuxt 官方文档:State Management
- Nuxt 官方文档:Deployment
视频资源
学习建议
- 第一遍重点看 Introduction、Installation、Data Fetching
- 第二遍开始结合自己的 Vue 项目理解 SSR 和服务端目录
- 如果你还没学透 Vue,不要急着上 Nuxt 的高级特性