Nuxt 3 是一个构建在 Vue 3 和 Nitro 之上的强大全栈框架,提供基于文件的路由、自动导入、服务端渲染和丰富的模块生态系统。无论你是构建内容站点、SaaS 仪表板还是全栈应用,Nuxt 3 都能让你以最少的配置快速交付。
Key Takeaways
- Nuxt 3 使用 pages/ 目录下的文件路由,支持动态参数、通配路由和嵌套布局
- Nitro 服务器引擎为服务器路由、API 端点和边缘部署提供通用输出
- 自动导入消除了 Vue API、组合式函数和工具函数的样板代码
- 内置的 useFetch、useAsyncData 和 useState 处理数据获取和状态管理
- 中间件(路由守卫)、布局和插件提供结构化的应用架构
- Nuxt 模块扩展功能:内容、图片、认证、SEO 等 200 多个社区模块
- 一条命令部署到 Vercel、Cloudflare Workers、Netlify 或任何 Node.js 服务器
- Nuxt 3 支持 SSR、SSG、ISR、SPA 和按路由混合渲染
Nuxt 3 入门
创建新的 Nuxt 3 项目只需一条命令。CLI 会生成一个带有 TypeScript 支持、开发服务器和热模块替换的最小项目。
# Create a new Nuxt 3 project
npx nuxi@latest init my-nuxt-app
# Navigate into the project
cd my-nuxt-app
# Install dependencies
npm install
# Start development server (http://localhost:3000)
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview项目结构
Nuxt 使用基于约定的目录结构。每个目录都有特定的用途,Nuxt 会自动发现其中的文件。
my-nuxt-app/
nuxt.config.ts # Nuxt configuration
app.vue # Root component
pages/ # File-based routing
index.vue # / route
about.vue # /about route
blog/
index.vue # /blog route
[slug].vue # /blog/:slug route
components/ # Auto-imported components
AppHeader.vue
AppFooter.vue
composables/ # Auto-imported composables
useAuth.ts
useApi.ts
layouts/ # Page layouts
default.vue
admin.vue
middleware/ # Route middleware
auth.ts
plugins/ # App plugins
analytics.ts
server/ # Server routes (Nitro)
api/
users.get.ts # GET /api/users
users.post.ts # POST /api/users
middleware/
log.ts
public/ # Static assets
assets/ # Build-processed assets基于文件的路由
Nuxt 根据 pages/ 目录中的 Vue 文件自动生成路由。文件路径直接映射到 URL 路径,支持动态参数、通配路由和嵌套路由。
<!-- pages/index.vue -->
<template>
<div>
<h1>Welcome to Nuxt 3</h1>
<NuxtLink to="/about">About</NuxtLink>
<NuxtLink to="/blog">Blog</NuxtLink>
</div>
</template>动态路由
使用方括号定义文件名中的动态段。参数可通过 useRoute 组合式函数获取。
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
// Access the dynamic route parameter
const route = useRoute()
const slug = route.params.slug
// Fetch blog post data
const { data: post } = await useFetch(
`/api/blog/\${slug}`
)
</script>
<template>
<article v-if="post">
<h1>{{ post.title }}</h1>
<div v-html="post.content" />
</article>
</template>通配路由和可选参数
使用展开语法实现通配路由,使用问号标记可选参数。
# Catch-all route: matches /docs/a, /docs/a/b, /docs/a/b/c
pages/docs/[...slug].vue
# Optional parameter: matches /users and /users/123
pages/users/[[id]].vue
# Route mapping examples:
# pages/index.vue -> /
# pages/about.vue -> /about
# pages/blog/index.vue -> /blog
# pages/blog/[slug].vue -> /blog/:slug
# pages/blog/[...slug].vue -> /blog/*
# pages/users-[group]/[id].vue -> /users-:group/:id嵌套路由
将 Vue 文件和匹配的目录并排放置来创建嵌套布局。父文件使用 NuxtPage 渲染子路由。
<!-- pages/dashboard.vue (parent layout) -->
<template>
<div>
<nav>
<NuxtLink to="/dashboard">Overview</NuxtLink>
<NuxtLink to="/dashboard/analytics">Analytics</NuxtLink>
<NuxtLink to="/dashboard/settings">Settings</NuxtLink>
</nav>
<!-- Child routes render here -->
<NuxtPage />
</div>
</template>
<!-- pages/dashboard/index.vue -->
<template>
<div>Dashboard Overview</div>
</template>
<!-- pages/dashboard/analytics.vue -->
<template>
<div>Analytics Page</div>
</template>服务器路由和 API 端点
Nuxt 3 包含由 Nitro 驱动的内置服务器。在 server/ 目录中创建文件来定义 API 端点。
定义 API 端点
在 server/api/ 或 server/routes/ 中创建文件来定义端点。文件名成为路由路径。
// server/api/users.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event)
const page = Number(query.page) || 1
return {
users: await fetchUsersFromDB(page),
total: await countUsers(),
}
})
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event)
if (!body.email || !body.name) {
throw createError({
statusCode: 400,
statusMessage: "Name and email are required",
})
}
return { user: await createUser(body) }
})
// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, "id")
const user = await getUserById(id)
if (!user) {
throw createError({ statusCode: 404, statusMessage: "User not found" })
}
return { user }
})服务器中间件
服务器中间件在路由匹配之前运行。用于认证、日志记录或 CORS 头。
// server/middleware/auth.ts
export default defineEventHandler((event) => {
const token = getHeader(event, "authorization")
// Skip auth for public routes
if (event.path.startsWith("/api/public")) return
if (!token) {
throw createError({
statusCode: 401,
statusMessage: "Unauthorized",
})
}
// Attach user info to the event context
event.context.user = verifyToken(token)
})
// server/middleware/logger.ts
export default defineEventHandler((event) => {
console.log(
`[\${new Date().toISOString()}] \${event.method} \${event.path}`
)
})服务器路由中的数据库访问
服务器路由在 Node.js 兼容环境中运行,可以访问数据库、文件系统和任何服务端库。
// server/utils/db.ts
import { drizzle } from "drizzle-orm/node-postgres"
import { Pool } from "pg"
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
})
export const db = drizzle(pool)
// server/api/posts.get.ts
import { db } from "~~/server/utils/db"
import { posts } from "~~/server/db/schema"
export default defineEventHandler(async () => {
return await db.select().from(posts).orderBy(posts.createdAt)
})内置组合式函数
Nuxt 为数据获取、状态管理和导航等常见任务提供组合式函数。它们是自动导入的且支持 SSR。
useFetch
数据获取的主要组合式函数。它处理 SSR 水合、缓存,并提供响应式的 data、error 和 pending 状态。
<script setup lang="ts">
// Basic usage - returns reactive data, pending, error, refresh
const { data, pending, error, refresh } = await useFetch("/api/posts")
// With options: query params, transform, caching
const { data: users } = await useFetch("/api/users", {
query: { page: 1, limit: 20 },
transform: (response) => response.users,
key: "users-page-1",
})
// Lazy fetch (non-blocking, loads after navigation)
const { data: comments } = useLazyFetch("/api/comments")
// Watch reactive source and refetch automatically
const page = ref(1)
const { data: items } = await useFetch("/api/items", {
query: { page },
watch: [page],
})
</script>
<template>
<div v-if="pending">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<ul v-else>
<li v-for="post in data" :key="post.id">{{ post.title }}</li>
</ul>
</template>useAsyncData
用于非简单 HTTP 请求的自定义异步操作。它用 SSR 水合支持包装任何异步函数。
<script setup lang="ts">
// Fetch from an external service
const { data: weather } = await useAsyncData(
"weather", // unique key for caching
() => $fetch("https://api.weather.com/current", {
params: { city: "london" }
})
)
// Combine multiple async operations
const { data: dashboard } = await useAsyncData(
"dashboard",
async () => {
const [users, orders, revenue] = await Promise.all([
$fetch("/api/users/count"),
$fetch("/api/orders/recent"),
$fetch("/api/revenue/monthly"),
])
return { users, orders, revenue }
}
)
</script>useState
共享的、支持 SSR 的响应式状态组合式函数。与 Vue ref 不同,useState 在 SSR 期间序列化并在组件间共享。
// composables/useCounter.ts
export const useCounter = () => {
const count = useState("counter", () => 0)
const increment = () => count.value++
const decrement = () => count.value--
return { count, increment, decrement }
}
// composables/useAuth.ts
export const useAuth = () => {
const user = useState("auth-user", () => null)
const isLoggedIn = computed(() => !!user.value)
const login = async (email: string, password: string) => {
const data = await $fetch("/api/auth/login", {
method: "POST", body: { email, password },
})
user.value = data.user
}
const logout = () => {
user.value = null
navigateTo("/login")
}
return { user, isLoggedIn, login, logout }
}useHead 和 useSeoMeta
响应式管理文档头部元数据。useSeoMeta 提供类型安全的 SEO 元标签管理。
<script setup lang="ts">
// Basic head management
useHead({
title: "My Page Title",
meta: [
{ name: "description", content: "Page description here" },
],
link: [
{ rel: "canonical", href: "https://example.com/page" },
],
})
// Type-safe SEO meta tags
useSeoMeta({
title: "Nuxt 3 Guide",
ogTitle: "Nuxt 3 Guide",
description: "Complete guide to building with Nuxt 3",
ogDescription: "Complete guide to building with Nuxt 3",
ogImage: "https://example.com/og.png",
twitterCard: "summary_large_image",
})
</script>Nitro 服务器引擎
Nitro 是驱动 Nuxt 3 的服务器引擎。它提供跨 Node.js、Cloudflare Workers、Deno、Bun 等平台的通用运行时。
Nitro 核心特性
Nitro 提供服务器路由热更新、自动 API 路由生成、内置缓存、存储层和跨平台部署预设。
缓存的服务器路由
使用 defineCachedEventHandler 缓存服务器路由响应。适用于昂贵的数据库查询或外部 API 调用。
// server/api/popular-posts.get.ts
export default defineCachedEventHandler(
async () => {
const posts = await db.select().from(postsTable)
.orderBy(desc(postsTable.views)).limit(20)
return { posts }
},
{ maxAge: 60 * 10, name: "popular-posts" }
)Nitro 存储层
Nitro 提供通用存储层,支持多种驱动:内存、文件系统、Redis、Cloudflare KV 等。
// nuxt.config.ts - configure storage
export default defineNuxtConfig({
nitro: {
storage: {
redis: { driver: "redis", host: "localhost", port: 6379 },
fs: { driver: "fs", base: "./data" },
},
},
})
// server/api/cache.ts - use storage
export default defineEventHandler(async () => {
const storage = useStorage("redis")
await storage.setItem("user:123", { name: "Alice", role: "admin" })
const user = await storage.getItem("user:123")
const keys = await storage.getKeys("user:")
return { user, keys }
})自动导入
Nuxt 自动导入 Vue API、组合式函数和工具函数。你不需要手动导入 ref、computed、useFetch 或 navigateTo。
<script setup lang="ts">
// All auto-imported - no import statements needed!
const count = ref(0) // Vue API
const doubled = computed(() => count.value * 2)
watch(count, (val) => console.log("Count:", val))
const route = useRoute() // Nuxt composables
const config = useRuntimeConfig()
const { data } = await useFetch("/api/data")
const goHome = () => navigateTo("/") // Navigation
</script>自定义组合式函数
在 composables/ 目录中创建组合式函数,它们会自动在整个应用中可用。
// composables/useApi.ts
export const useApi = <T>(url: string, options = {}) => {
const config = useRuntimeConfig()
return useFetch<T>(url, {
baseURL: config.public.apiBase,
headers: {
Authorization: `Bearer \${useAuth().token.value}`,
},
...options,
})
}
// composables/useLocalStorage.ts
export const useLocalStorage = <T>(key: string, defaultValue: T) => {
const data = useState<T>(key, () => defaultValue)
if (import.meta.client) {
const stored = localStorage.getItem(key)
if (stored) data.value = JSON.parse(stored)
watch(data, (val) => {
localStorage.setItem(key, JSON.stringify(val))
}, { deep: true })
}
return data
}Nuxt 模块
模块通过插件系统扩展 Nuxt 功能。Nuxt 生态系统包含 200 多个模块。
常用模块
| Module | Purpose | Package |
|---|---|---|
| Nuxt Content | File-based CMS with Markdown, MDX, YAML | @nuxt/content |
| Nuxt Image | Automatic image optimization and resizing | @nuxt/image |
| Nuxt UI | Component library with Tailwind CSS | @nuxt/ui |
| Nuxt Auth Utils | Session-based authentication | nuxt-auth-utils |
| Nuxt SEO | All-in-one SEO toolkit | @nuxtjs/seo |
| VueUse | Collection of Vue composition utilities | @vueuse/nuxt |
| Pinia | State management for Vue | @pinia/nuxt |
| Nuxt i18n | Internationalization and localization | @nuxtjs/i18n |
安装模块
从 npm 安装模块并添加到 nuxt.config.ts 的 modules 数组中。
# Install a module
npx nuxi module add @nuxt/content
# Or manually install and configure
npm install @nuxt/image @pinia/nuxt// nuxt.config.ts
export default defineNuxtConfig({
modules: [
"@nuxt/content",
"@nuxt/image",
"@pinia/nuxt",
"@nuxtjs/i18n",
],
// Module-specific configuration
content: {
highlight: {
theme: "github-dark",
},
},
image: {
quality: 80,
formats: ["avif", "webp"],
},
i18n: {
locales: ["en", "fr", "de"],
defaultLocale: "en",
},
})路由中间件
中间件是渲染页面前运行的导航守卫。Nuxt 支持三种类型:匿名、命名和全局中间件。
命名中间件
在 middleware/ 目录中创建中间件文件,在页面组件中通过 definePageMeta 引用。
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { isLoggedIn } = useAuth()
if (!isLoggedIn.value) return navigateTo("/login")
})
// middleware/role.ts
export default defineNuxtRouteMiddleware((to) => {
const { user } = useAuth()
if (to.meta.role && user.value?.role !== to.meta.role) {
return navigateTo("/unauthorized")
}
})<!-- pages/dashboard.vue -->
<script setup lang="ts">
definePageMeta({ middleware: ["auth"] })
</script>
<!-- pages/admin.vue - multiple middleware -->
<script setup lang="ts">
definePageMeta({ middleware: ["auth", "role"], role: "admin" })
</script>全局中间件
middleware/ 中带 .global 后缀的文件会在每次路由导航时自动运行。
// middleware/analytics.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// Runs on every route change
if (import.meta.client) {
trackPageView(to.fullPath)
}
})布局
布局是包裹页面的组件。用于共享 UI 元素如页头、侧边栏和页脚。在 layouts/ 目录中定义。
<!-- layouts/default.vue -->
<template>
<div>
<AppHeader />
<main>
<slot />
</main>
<AppFooter />
</div>
</template>自定义布局
为应用的不同部分创建多个布局。页面通过 definePageMeta 选择布局。
<!-- layouts/admin.vue -->
<template>
<div style="display: flex">
<AdminSidebar />
<main style="flex: 1; padding: 2rem">
<slot />
</main>
</div>
</template>
<!-- pages/admin/index.vue -->
<script setup lang="ts">
definePageMeta({
layout: "admin",
})
</script>
<template>
<div>
<h1>Admin Dashboard</h1>
</div>
</template>插件
插件在应用初始化时运行,可以访问 Nuxt 应用实例。用于注册全局组件、指令或第三方库。
创建插件
在 plugins/ 目录中创建文件。它们会自动注册并在渲染根组件之前运行。
// plugins/api.ts
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig()
const api = $fetch.create({
baseURL: config.public.apiBase,
onRequest({ options }) {
const token = useCookie("auth-token")
if (token.value) {
options.headers.set("Authorization", `Bearer \${token.value}`)
}
},
onResponseError({ response }) {
if (response.status === 401) navigateTo("/login")
},
})
return { provide: { api } }
})
// Usage: const { $api } = useNuxtApp()
// const data = await $api("/users")渲染模式
Nuxt 3 支持多种渲染策略,可以全局配置或按路由配置。
服务端渲染 (SSR)
默认模式。页面在服务器上为每个请求渲染,提供快速的首次内容绘制和 SEO 优势。
// nuxt.config.ts - SSR is enabled by default
export default defineNuxtConfig({
ssr: true, // default
})静态站点生成 (SSG)
在构建时预渲染所有页面为静态 HTML。适合内容站点、文档和营销页面。
# Pre-render all pages as static HTML
npx nuxi generate
# Output is in .output/public/ - deploy to any CDN混合渲染
使用 nuxt.config.ts 中的路由规则为每个路由配置不同的渲染策略。
// nuxt.config.ts - hybrid rendering
export default defineNuxtConfig({
routeRules: {
"/": { prerender: true }, // Static at build
"/about": { prerender: true },
"/blog/**": { isr: 60 }, // ISR: regen every 60s
"/admin/**": { ssr: false }, // SPA: client-only
"/api/**": { cache: { maxAge: 300 }, cors: true },
"/old-page": { redirect: "/new-page" },
},
})部署
Nuxt 3 通过零配置预设部署到多个平台。Nitro 自动检测部署平台并优化输出。
部署到 Vercel
Vercel 原生支持 Nuxt。推送到 Git 即可自动检测和部署。
# Vercel auto-detects Nuxt - just push to Git
npx vercel
# Or set preset explicitly in nuxt.config.ts:
# nitro: { preset: "vercel" }部署到 Cloudflare Workers
Nuxt 可在 Cloudflare Workers 边缘运行,实现全球超低延迟。
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: "cloudflare-pages",
},
})
// Deploy with Wrangler
// npx wrangler pages deploy .output/publicNode.js 服务器
使用 PM2、Docker 或云 VM 部署到任何 Node.js 服务器。
# Build and start
npm run build
node .output/server/index.mjs
# PM2 process management
pm2 start .output/server/index.mjs --name my-nuxt-app
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY .output .output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]Nuxt vs Next.js
Nuxt 和 Next.js 分别是 Vue 和 React 的主流元框架。以下是它们的对比。
| 功能 | Nuxt 3 | Next.js 15 |
|---|---|---|
| Base Framework | Vue 3 | React 19 |
| Build Tool | Vite | Turbopack / webpack |
| Server Engine | Nitro (H3) | Built-in (Node.js) |
| Auto-Imports | Built-in (composables, components, Vue APIs) | Not built-in |
| File Routing | pages/ directory | app/ directory |
| Data Fetching | useFetch, useAsyncData | Server Components, fetch() |
| State Management | useState (built-in) + Pinia | React Context + Zustand/Jotai |
| Rendering Modes | SSR, SSG, ISR, SPA, Hybrid per-route | SSR, SSG, ISR, SPA, Streaming |
| Edge Deployment | Cloudflare Workers, Deno, Bun | Vercel Edge, Cloudflare |
| TypeScript | Built-in, auto-generated types | Built-in |
| Module Ecosystem | 200+ modules | npm packages (no module system) |
| Learning Curve | Lower (Vue is simpler) | Moderate (React + RSC complexity) |
常见问题
Nuxt 2 和 Nuxt 3 有什么区别?
Nuxt 3 是基于 Vue 3、Vite 和 Nitro 的完全重写。性能更好,支持 TypeScript、自动导入、组合式 API、混合渲染和新的服务器引擎。
Nuxt 3 可以用于生产环境吗?
可以。Nuxt 3 于 2022 年 11 月发布稳定版,积极维护中。许多大公司在生产环境使用 Nuxt 3。
我的项目应该用 Nuxt 还是普通 Vue?
如果需要 SEO、服务端渲染、文件路由或全栈框架,使用 Nuxt。客户端 SPA 或需要完全控制构建配置时使用普通 Vue。
useFetch 和 useAsyncData 有什么区别?
useFetch 是 useAsyncData 的便捷封装,自动处理基于 URL 的数据获取和缓存。useAsyncData 更灵活,可用于任何异步函数。
Nuxt 可以用于静态站点吗?
可以。运行 npx nuxi generate 将所有页面预渲染为静态 HTML。也支持混合渲染。
Nuxt 3 的自动导入如何工作?
Nuxt 扫描 composables/、components/ 和 utils/ 目录并自动导入其导出。Vue API 也自动导入。这在构建时通过代码转换完成,无运行时开销。
Nitro 是什么?为什么重要?
Nitro 是驱动 Nuxt 3 的服务器引擎。它提供可部署到 Node.js、Cloudflare Workers、Deno 等的通用运行时,处理服务器路由、缓存和存储。
如何给 Nuxt 应用添加认证?
使用 nuxt-auth-utils 模块实现会话认证,或 sidebase-auth 实现 OAuth。也可以使用服务器中间件和 useState 自定义实现。