Chapter 07

Nuxt 3:全栈 Vue 框架

从零到全栈:Nuxt 3 的文件系统路由、自动导入、Server API 目录,让你用一套代码构建完整的 Web 应用

7.1 Nuxt 3 是什么?

Nuxt 3 是基于 Vue 3 的全栈框架,在 Vue 的基础上提供了:

# 使用官方脚手架
npx nuxi@latest init my-nuxt-app
cd my-nuxt-app
npm install
npm run dev   # http://localhost:3000

7.2 项目目录结构

my-nuxt-app/
├── .nuxt/              # 自动生成,勿手动修改
├── assets/             # 需要构建工具处理的静态资源(图片、字体、CSS)
├── components/         # Vue 组件(自动导入)
│   ├── AppHeader.vue
│   └── ui/             # 子目录组件名:UiButton
│       └── Button.vue
├── composables/        # Composables(自动导入)
│   └── useCounter.ts
├── layouts/            # 布局组件
│   ├── default.vue     # 默认布局
│   └── auth.vue
├── middleware/         # 路由中间件
│   └── auth.ts
├── pages/              # 页面(自动生成路由)
│   ├── index.vue       # /
│   ├── about.vue       # /about
│   └── users/
│       ├── index.vue   # /users
│       └── [id].vue    # /users/:id(动态路由)
├── plugins/            # Nuxt 插件(在 Vue 实例创建前运行)
├── public/             # 直接提供的静态资源(无需构建)
├── server/             # 服务端代码(仅在服务器运行)
│   ├── api/
│   │   └── users.get.ts  # GET /api/users
│   ├── middleware/
│   └── utils/
├── utils/              # 工具函数(自动导入)
├── app.vue             # 应用根组件
├── nuxt.config.ts      # Nuxt 配置
└── package.json

7.3 文件系统路由

Nuxt 3 自动将 pages/ 目录下的 Vue 文件转换为路由,无需手动配置 Vue Router:

文件路径生成的路由说明
pages/index.vue/首页
pages/about.vue/about普通页面
pages/users/index.vue/users目录索引页
pages/users/[id].vue/users/:id动态路由
pages/users/[id]/posts.vue/users/:id/posts嵌套动态路由
pages/[...slug].vue/:slug(.*)*Catch-all(404 等)
pages/blog/[[page]].vue/blog 或 /blog/2可选参数
<script setup lang="ts">
// Nuxt 自动导入 useRoute,无需 import
const route = useRoute()
const id = route.params.id

// useFetch 也是自动导入的(Nuxt 内置)
const { data: user } = await useFetch(`/api/users/${id}`)

// 定义页面元信息(SEO)
useHead({
  title: () => user.value?.name ?? '用户详情',
  meta: [{ name: 'description', content: '用户个人主页' }]
})
</script>

7.4 自动导入(Auto-imports)

Nuxt 3 的一大特色是自动导入:无需手动 import,就可以直接使用以下内容:

Vue 核心 API
ref、reactive、computed、watch、watchEffect、onMounted 等,所有 Composition API 函数
Nuxt 内置
useFetch、useAsyncData、useHead、useRoute、useRouter、useState、useCookie、useNuxtApp 等
components/ 目录
所有 Vue 组件自动按需导入,子目录组件会添加前缀(ui/Button.vue → <UiButton>)
composables/ 目录
所有 composable 函数自动导入,支持嵌套目录
utils/ 目录
所有工具函数自动导入(注意:与 composables 不同,utils 不包含响应式逻辑)
自动导入的陷阱

自动导入仅在 .vue.tscomposables/utils/ 目录内)文件中生效。在 server/ 目录下不适用 Vue 相关的自动导入(因为服务端不运行 Vue)。如果 IDE 找不到类型,可以运行 npx nuxi prepare 生成类型文件。

7.5 Layouts 布局系统

<template>
  <div>
    <AppHeader />  <!-- 自动导入 -->
    <main>
      <slot />  <!-- 页面内容渲染到这里 -->
    </main>
    <AppFooter />
  </div>
</template>
<script setup>
// 指定使用 auth 布局(layouts/auth.vue)
definePageMeta({
  layout: 'auth'
})
</script>

7.6 Server API 路由

server/api/ 目录下的文件会自动成为 API 端点,基于 H3(轻量 HTTP 框架):

// GET /api/users
export default defineEventHandler(async (event) => {
  // 只在服务器运行,可以安全地访问数据库
  const db = useDatabase()
  const users = await db.query('SELECT * FROM users')
  return users  // 自动序列化为 JSON
})
// DELETE /api/users/:id
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id')
  const body = await readBody<{ reason: string }>(event)

  // 验证身份(使用请求头)
  const token = getHeader(event, 'authorization')
  if (!token) throw createError({ statusCode: 401, message: '未授权' })

  await deleteUser(id)
  return { success: true }
})
文件名HTTP 方法URL
server/api/users.get.tsGET/api/users
server/api/users.post.tsPOST/api/users
server/api/users/[id].get.tsGET/api/users/:id
server/api/users/[id].delete.tsDELETE/api/users/:id
server/api/users/index.ts所有方法/api/users

7.7 nuxt.config.ts 配置

export default defineNuxtConfig({
  // 开发工具(开发环境自动启用 Vue DevTools)
  devtools: { enabled: true },

  // 模块(扩展 Nuxt 功能)
  modules: [
    '@nuxtjs/tailwindcss',
    '@pinia/nuxt',
    '@nuxt/image',
    'nuxt-auth-utils'
  ],

  // CSS 全局文件
  css: ['~/assets/css/main.css'],

  // 运行时配置(区分公开和私有)
  runtimeConfig: {
    // 私有:仅服务端可用
    dbUrl: process.env.DATABASE_URL,
    jwtSecret: process.env.JWT_SECRET,
    // 公开:客户端和服务端都可用
    public: {
      apiBase: '/api',
      appName: '我的应用'
    }
  },

  // TypeScript 配置
  typescript: {
    strict: true
  }
})
Nuxt 3 vs 纯 Vue 3 的选择

如果你的应用需要 SEO、快速首屏加载、或需要后端 API,选择 Nuxt 3。如果只是纯前端 SPA(如后台管理系统),选择 Vite + Vue 3 即可。Nuxt 3 在 SPA 项目中反而会增加不必要的复杂度。

7.5 Nuxt 4 迁移预览

Nuxt 4(计划与 Nuxt 3.x 并行提供兼容模式)带来了几个重要改变,可以提前在 Nuxt 3 中启用测试:

app/ 目录结构调整
Nuxt 4 将应用代码迁移到 app/ 子目录(类似 Next.js 的 app/),项目根目录更清晰。在 Nuxt 3 中通过 future.compatibilityVersion: 4 提前启用。
共享数据目录 shared/
新增 shared/ 目录,用于存放服务端和客户端都需要使用的工具函数和类型,解决跨端代码复用问题。
useId() 唯一 ID
新增 useId() composable,生成 SSR 安全的唯一 ID,用于无障碍 label 关联、列表 key 等场景,避免服务端客户端 ID 不一致导致的水合错误。
性能优化
Nuxt 4 使用 Vite 5 + Rolldown(Rust 重写的 rollup),构建速度大幅提升。同时改进了组件懒加载策略,减少首屏 JS 体积。
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 4  // 提前测试 Nuxt 4 行为
  },
  // Nuxt 4 下 app/ 目录作为应用根目录
  // pages/ → app/pages/
  // composables/ → app/composables/
  // components/ → app/components/
})

7.6 Nuxt DevTools

Nuxt DevTools 是官方提供的可视化调试工具,在开发模式下通过浮动按钮打开。它提供了组件树分析、路由列表、模块状态、性能分析等功能,极大提升了 Nuxt 项目的调试体验。

export default defineNuxtConfig({
  devtools: {
    enabled: true,     // 启用 DevTools(开发模式默认已启用)
    timeline: {
      enabled: true    // 启用时间线功能,追踪异步操作
    }
  }
})
常见误区:在 server/ 目录中使用 Vue 响应式 API

server/ 目录下的代码运行在 Node.js 服务器端,没有 Vue 运行时环境。不能在 API 路由中使用 ref()computed() 等 Vue API,也不能使用 useRuntimeConfig() 以外的 Nuxt Composable。服务端代码是普通的 Node.js/TypeScript 函数,只有 Nitro 提供的 defineEventHandlerreadBodycreateError 等工具可用。

本章小结

Nuxt 3 是基于 Vue 3 的全栈框架,核心特性:文件系统路由(pages/ 自动生成路由)、自动导入(components/、composables/ 免 import)、服务端 API(server/api/ 中的 Nitro 路由)、混合渲染(routeRules 按路由配置 SSR/SSG/ISR/CSR)。Nuxt 3 的 defineNuxtConfig 是配置中心,runtimeConfig 安全传递环境变量。Nuxt 4 带来 app/ 目录结构和更多性能改进,可通过 future.compatibilityVersion: 4 提前体验。