name: nuxt-core description: | Nuxt 4 核心框架基础:项目设置、配置、路由、 SEO、错误处理和目录结构。
使用场景:创建新的 Nuxt 4 项目,配置 nuxt.config.ts, 设置路由和中间件,使用 useHead/useSeoMeta 实现 SEO, 通过 error.vue 和 NuxtErrorBoundary 处理错误,或理解 Nuxt 4 目录结构。
关键词:Nuxt 4, nuxt.config.ts, 文件路由, pages 目录, definePageMeta, useHead, useSeoMeta, error.vue, NuxtErrorBoundary, 中间件, navigateTo, NuxtLink, app 目录, 运行时配置 license: MIT metadata: version: 4.0.0 author: Claude Skills Maintainers category: Framework framework: Nuxt framework-version: 4.x last-verified: 2025-12-28
Nuxt 4 核心基础
Nuxt 4 应用程序的项目设置、配置、路由、SEO 和错误处理。
快速参考
版本要求
| 包 | 最低 | 推荐 |
|---|---|---|
| nuxt | 4.0.0 | 4.2.x |
| vue | 3.5.0 | 3.5.x |
| nitro | 2.10.0 | 2.12.x |
| vite | 6.0.0 | 6.2.x |
| typescript | 5.0.0 | 5.x |
关键命令
# 创建新项目
bunx nuxi@latest init my-app
# 开发
bun run dev
# 构建生产版本
bun run build
# 预览生产构建
bun run preview
# 类型检查
bun run postinstall # 生成 .nuxt 目录
bunx nuxi typecheck
# 添加页面/组件/可组合项
bunx nuxi add page about
bunx nuxi add component MyButton
bunx nuxi add composable useAuth
目录结构 (Nuxt v4)
my-nuxt-app/
├── app/ # v4 中的默认 srcDir
│ ├── assets/ # 构建处理的资产(CSS、图片)
│ ├── components/ # 自动导入的 Vue 组件
│ ├── composables/ # 自动导入的可组合项
│ ├── layouts/ # 布局组件
│ ├── middleware/ # 路由中间件
│ ├── pages/ # 文件路由
│ ├── plugins/ # Nuxt 插件
│ ├── utils/ # 自动导入的实用函数
│ ├── app.vue # 主应用组件
│ ├── app.config.ts # 应用级运行时配置
│ ├── error.vue # 错误页面组件
│ └── router.options.ts # 路由器配置
│
├── server/ # 服务器端代码(Nitro)
│ ├── api/ # API 端点
│ ├── middleware/ # 服务器中间件
│ ├── plugins/ # Nitro 插件
│ ├── routes/ # 服务器路由
│ └── utils/ # 服务器实用工具
│
├── public/ # 静态资产(从根目录提供)
├── shared/ # 共享代码(应用 + 服务器)
├── content/ # Nuxt Content 文件(如使用)
├── layers/ # Nuxt 层
├── modules/ # 本地模块
├── .nuxt/ # 生成文件(git 忽略)
├── .output/ # 构建输出(git 忽略)
├── nuxt.config.ts # Nuxt 配置
├── tsconfig.json # TypeScript 配置
└── package.json # 依赖项
v4 中的关键变化:app/ 目录现在是默认的 srcDir。所有应用代码放在 app/ 中,服务器代码留在 server/。
何时加载参考
加载 references/configuration-deep.md 当:
- 配置高级 nuxt.config.ts 选项
- 设置模块和插件
- 自定义 Vite 或 Nitro 配置
- 配置实验性功能
加载 references/routing-advanced.md 当:
- 实现复杂路由模式
- 创建带有身份验证的路由中间件
- 使用捕获所有路由或可选参数
- 配置路由器选项
加载 references/plugins-architecture.md 当:
- 创建 Nuxt 插件
- 注入全局实用工具或可组合项
- 集成第三方库
- 理解插件执行顺序
配置
基本 nuxt.config.ts
export default defineNuxtConfig({
// 启用 Nuxt 4 功能
future: {
compatibilityVersion: 4
},
// 开发工具
devtools: { enabled: true },
// 模块
modules: [
'@nuxt/ui',
'@nuxt/content',
'@nuxt/image'
],
// 运行时配置(环境变量)
runtimeConfig: {
// 仅服务器端(不暴露给客户端)
apiSecret: process.env.API_SECRET,
databaseUrl: process.env.DATABASE_URL,
// 公共(客户端 + 服务器)
public: {
apiBase: process.env.API_BASE || 'https://api.example.com',
appName: 'My App'
}
},
// 应用配置
app: {
head: {
title: 'My Nuxt App',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
]
}
},
// Nitro 配置(服务器)
nitro: {
preset: 'cloudflare-pages'
},
// TypeScript
typescript: {
strict: true,
typeCheck: true
}
})
运行时配置使用
// 在可组合项或组件中
const config = useRuntimeConfig()
// 公共值(客户端 + 服务器)
const apiBase = config.public.apiBase
// 仅服务器端值(仅在 server/ 中)
const apiSecret = config.apiSecret // 在客户端为 undefined!
关键规则:在生产环境中,始终使用 useRuntimeConfig() 而不是 process.env 处理环境变量。
应用配置 vs 运行时配置
| 特性 | 应用配置 | 运行时配置 |
|---|---|---|
| 位置 | app.config.ts |
nuxt.config.ts |
| 热重载 | 是 | 否 |
| 机密 | 否 | 是(仅服务器端) |
| 使用场景 | UI 设置、主题 | API 密钥、URL |
// app/app.config.ts - UI 设置(可热重载)
export default defineAppConfig({
theme: {
primaryColor: '#3490dc'
},
ui: {
rounded: 'lg'
}
})
// 使用
const appConfig = useAppConfig()
const color = appConfig.theme.primaryColor
路由
文件路由
app/pages/
├── index.vue → /
├── about.vue → /about
├── users/
│ ├── index.vue → /users
│ └── [id].vue → /users/:id
└── blog/
├── index.vue → /blog
├── [slug].vue → /blog/:slug
└── [...slug].vue → /blog/*(捕获所有)
动态路由
<!-- app/pages/users/[id].vue -->
<script setup lang="ts">
const route = useRoute()
// 获取路由参数
const userId = route.params.id
// 响应式(路由变化时更新)
const userId = computed(() => route.params.id)
// 获取用户数据
const { data: user } = await useFetch(`/api/users/${userId.value}`)
</script>
<template>
<div>
<h1>{{ user?.name }}</h1>
</div>
</template>
导航
<script setup>
const goToUser = (id: string) => {
navigateTo(`/users/${id}`)
}
const goBack = () => {
navigateTo(-1) // 返回历史记录
}
// 带选项
const goToLogin = () => {
navigateTo('/login', {
replace: true, // 替换当前历史记录条目
external: false // 内部导航
})
}
</script>
<template>
<!-- 声明式导航 -->
<NuxtLink to="/about">关于</NuxtLink>
<NuxtLink :to="`/users/${user.id}`">查看用户</NuxtLink>
<!-- 预取(默认:悬停) -->
<NuxtLink to="/dashboard" prefetch>仪表盘</NuxtLink>
<!-- 不预取 -->
<NuxtLink to="/admin" :prefetch="false">管理员</NuxtLink>
</template>
路由中间件
// app/middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
return navigateTo('/login')
}
})
<!-- app/pages/dashboard.vue -->
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
</script>
全局中间件
// app/middleware/analytics.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// 在每次路由变化时运行
if (import.meta.client) {
window.gtag?.('event', 'page_view', {
page_path: to.path
})
}
})
页面元数据
<script setup lang="ts">
definePageMeta({
title: '仪表盘',
middleware: ['auth'],
layout: 'admin',
pageTransition: { name: 'fade' },
keepalive: true
})
</script>
SEO 和元标签
useSeoMeta(推荐)
<script setup lang="ts">
useSeoMeta({
title: '我的页面标题',
description: '搜索引擎的页面描述',
ogTitle: '我的页面标题',
ogDescription: '页面描述',
ogImage: 'https://example.com/og-image.jpg',
ogUrl: 'https://example.com/my-page',
twitterCard: 'summary_large_image',
twitterTitle: '我的页面标题',
twitterDescription: '页面描述',
twitterImage: 'https://example.com/og-image.jpg'
})
</script>
useHead(更多控制)
<script setup lang="ts">
useHead({
title: '我的页面标题',
meta: [
{ name: 'description', content: '页面描述' },
{ property: 'og:title', content: '我的页面标题' }
],
link: [
{ rel: 'canonical', href: 'https://example.com/my-page' }
],
script: [
{ src: 'https://example.com/script.js', defer: true }
]
})
</script>
动态元标签
<script setup lang="ts">
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)
useSeoMeta({
title: () => post.value?.title,
description: () => post.value?.excerpt,
ogImage: () => post.value?.image
})
</script>
标题模板
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
titleTemplate: '%s | My App' // "页面标题 | 我的应用"
}
}
})
错误处理
错误页面
<!-- app/error.vue -->
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps<{
error: NuxtError
}>()
const handleError = () => {
clearError({ redirect: '/' })
}
</script>
<template>
<div class="error-page">
<h1>{{ error.statusCode }}</h1>
<p>{{ error.message }}</p>
<button @click="handleError">返回首页</button>
</div>
</template>
错误边界(组件级)
<template>
<NuxtErrorBoundary @error="handleError">
<template #error="{ error, clearError }">
<div class="error-container">
<h2>出错了</h2>
<p>{{ error.message }}</p>
<button @click="clearError">重试</button>
</div>
</template>
<!-- 您的组件内容 -->
<MyComponent />
</NuxtErrorBoundary>
</template>
<script setup>
const handleError = (error: Error) => {
console.error('组件错误:', error)
// 发送到错误跟踪服务
}
</script>
抛出错误
// 在页面或组件中
throw createError({
statusCode: 404,
statusMessage: '页面未找到',
fatal: true // 显示错误页面,停止渲染
})
// 非致命错误(内联显示)
throw createError({
statusCode: 400,
message: '输入无效'
})
API 错误处理
const { data, error } = await useFetch('/api/users')
if (error.value) {
// 优雅处理错误
showError({
statusCode: error.value.statusCode,
message: error.value.message
})
}
常见反模式
使用 process.env 替代运行时配置
// 错误 - 在生产环境中无效!
const apiUrl = process.env.API_URL
// 正确
const config = useRuntimeConfig()
const apiUrl = config.public.apiBase
缺少中间件守卫
// 错误 - 无返回,中间件继续
export default defineNuxtRouteMiddleware((to) => {
const { isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
navigateTo('/login') // 缺少返回!
}
})
// 正确
export default defineNuxtRouteMiddleware((to) => {
const { isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
return navigateTo('/login') // 返回停止中间件链
}
})
非响应式路由参数
// 错误 - 非响应式
const userId = route.params.id
// 正确 - 响应式
const userId = computed(() => route.params.id)
故障排除
构建错误 / 类型错误:
rm -rf .nuxt .output node_modules/.vite && bun install && bun run dev
路由未找到:
- 检查文件是否在
app/pages/(而非根pages/) - 验证文件扩展名为
.vue - 检查动态参数
[id].vue中的拼写错误
中间件不运行:
- 确保全局中间件文件有
.global.ts后缀 - 检查
definePageMeta({ middleware: 'name' })与文件名匹配 - 验证中间件返回
navigateTo()或什么都不返回
元标签不更新:
- 使用响应式值:
title: () => post.value?.title - 确保
useSeoMeta在<script setup>中调用
相关技能
- nuxt-data:可组合项、数据获取、状态管理
- nuxt-server:服务器路由、API 模式、数据库集成
- nuxt-production:性能、测试、部署
- nuxt-ui-v4:Nuxt UI 组件库
可用模板
查看 templates/ 目录:
- 生产就绪的
nuxt.config.ts - 结构良好的
app.vue - 中间件示例
版本:4.0.0 | 最后更新:2025-12-28 | 许可证:MIT