DevToolBox免费
博客

Nuxt 3 完全指南:Vue.js 全栈框架

24 min read作者 DevToolBox Team

Nuxt 3 是一个构建在 Vue 3 和 Nitro 之上的强大全栈框架,提供基于文件的路由、自动导入、服务端渲染和丰富的模块生态系统。无论你是构建内容站点、SaaS 仪表板还是全栈应用,Nuxt 3 都能让你以最少的配置快速交付。

TL;DR: Nuxt 3 是由 Nitro 驱动的全栈 Vue 框架。它具有文件路由、自动导入、内置 SSR/SSG/ISR、useState 和 useFetch 等组合式函数、服务器路由、中间件、布局和模块生态系统。可零配置部署到 Vercel、Cloudflare Workers 或 Node.js。

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 多个模块。

常用模块

ModulePurposePackage
Nuxt ContentFile-based CMS with Markdown, MDX, YAML@nuxt/content
Nuxt ImageAutomatic image optimization and resizing@nuxt/image
Nuxt UIComponent library with Tailwind CSS@nuxt/ui
Nuxt Auth UtilsSession-based authenticationnuxt-auth-utils
Nuxt SEOAll-in-one SEO toolkit@nuxtjs/seo
VueUseCollection of Vue composition utilities@vueuse/nuxt
PiniaState management for Vue@pinia/nuxt
Nuxt i18nInternationalization 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/public

Node.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 3Next.js 15
Base FrameworkVue 3React 19
Build ToolViteTurbopack / webpack
Server EngineNitro (H3)Built-in (Node.js)
Auto-ImportsBuilt-in (composables, components, Vue APIs)Not built-in
File Routingpages/ directoryapp/ directory
Data FetchinguseFetch, useAsyncDataServer Components, fetch()
State ManagementuseState (built-in) + PiniaReact Context + Zustand/Jotai
Rendering ModesSSR, SSG, ISR, SPA, Hybrid per-routeSSR, SSG, ISR, SPA, Streaming
Edge DeploymentCloudflare Workers, Deno, BunVercel Edge, Cloudflare
TypeScriptBuilt-in, auto-generated typesBuilt-in
Module Ecosystem200+ modulesnpm packages (no module system)
Learning CurveLower (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 自定义实现。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

{ }JSON FormatterJSON Validator

相关文章

Gatsby.js 完全指南:React 静态站点生成器

掌握 Gatsby.js,包括 GraphQL 数据层、插件、图片优化、SSR/DSG、CMS 集成与部署。

Deno 完全指南:安全的 JavaScript 运行时

掌握 Deno 运行时,包括安全权限、TypeScript 支持、标准库、HTTP 服务器、测试与 Deno Deploy。

SWC 完全指南:Rust 驱动的超快 JavaScript 编译器

掌握 SWC 超快编译,包括配置、转换、压缩、框架集成与从 Babel 迁移。