nuxt-core
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNuxt 4 Core Fundamentals
Nuxt 4 核心框架基础
Project setup, configuration, routing, SEO, and error handling for Nuxt 4 applications.
Nuxt 4 应用的项目搭建、配置、路由、SEO 以及错误处理指南。
Quick Reference
快速参考
Version Requirements
版本要求
| Package | Minimum | Recommended |
|---|---|---|
| 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 |
| 包名 | 最低版本 | 推荐版本 |
|---|---|---|
| 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 |
Key Commands
关键命令
bash
undefinedbash
undefinedCreate new project
创建新项目
bunx nuxi@latest init my-app
bunx nuxi@latest init my-app
Development
开发模式
bun run dev
bun run dev
Build for production
生产构建
bun run build
bun run build
Preview production build
预览生产构建产物
bun run preview
bun run preview
Type checking
类型检查
bun run postinstall # Generates .nuxt directory
bunx nuxi typecheck
bun run postinstall # 生成 .nuxt 目录
bunx nuxi typecheck
Add a page/component/composable
添加页面/组件/可组合函数
bunx nuxi add page about
bunx nuxi add component MyButton
bunx nuxi add composable useAuth
undefinedbunx nuxi add page about
bunx nuxi add component MyButton
bunx nuxi add composable useAuth
undefinedDirectory Structure (Nuxt v4)
Nuxt v4 目录结构
my-nuxt-app/
├── app/ # Default srcDir in v4
│ ├── assets/ # Build-processed assets (CSS, images)
│ ├── components/ # Auto-imported Vue components
│ ├── composables/ # Auto-imported composables
│ ├── layouts/ # Layout components
│ ├── middleware/ # Route middleware
│ ├── pages/ # File-based routing
│ ├── plugins/ # Nuxt plugins
│ ├── utils/ # Auto-imported utility functions
│ ├── app.vue # Main app component
│ ├── app.config.ts # App-level runtime config
│ ├── error.vue # Error page component
│ └── router.options.ts # Router configuration
│
├── server/ # Server-side code (Nitro)
│ ├── api/ # API endpoints
│ ├── middleware/ # Server middleware
│ ├── plugins/ # Nitro plugins
│ ├── routes/ # Server routes
│ └── utils/ # Server utilities
│
├── public/ # Static assets (served from root)
├── shared/ # Shared code (app + server)
├── content/ # Nuxt Content files (if using)
├── layers/ # Nuxt layers
├── modules/ # Local modules
├── .nuxt/ # Generated files (git ignored)
├── .output/ # Build output (git ignored)
├── nuxt.config.ts # Nuxt configuration
├── tsconfig.json # TypeScript configuration
└── package.json # DependenciesKey Change in v4: The directory is now the default . All app code goes in , server code stays in .
app/srcDirapp/server/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/srcDirapp/server/When to Load References
何时加载参考文档
Load when:
references/configuration-deep.md- Configuring advanced nuxt.config.ts options
- Setting up modules and plugins
- Customizing Vite or Nitro configuration
- Configuring experimental features
Load when:
references/routing-advanced.md- Implementing complex routing patterns
- Creating route middleware with authentication
- Using catch-all routes or optional parameters
- Configuring router options
Load when:
references/plugins-architecture.md- Creating Nuxt plugins
- Injecting global utilities or composables
- Integrating third-party libraries
- Understanding plugin execution order
当以下情况时加载 :
references/configuration-deep.md- 配置 nuxt.config.ts 的高级选项
- 设置模块与插件
- 自定义 Vite 或 Nitro 配置
- 配置实验性功能
当以下情况时加载 :
references/routing-advanced.md- 实现复杂的路由模式
- 创建带身份验证的路由中间件
- 使用通配符路由或可选参数
- 配置路由选项
当以下情况时加载 :
references/plugins-architecture.md- 创建 Nuxt 插件
- 注入全局工具或可组合函数
- 集成第三方库
- 理解插件执行顺序
Configuration
配置
Basic nuxt.config.ts
基础 nuxt.config.ts
typescript
export default defineNuxtConfig({
// Enable Nuxt 4 features
future: {
compatibilityVersion: 4
},
// Development tools
devtools: { enabled: true },
// Modules
modules: [
'@nuxt/ui',
'@nuxt/content',
'@nuxt/image'
],
// Runtime config (environment variables)
runtimeConfig: {
// Server-only (not exposed to client)
apiSecret: process.env.API_SECRET,
databaseUrl: process.env.DATABASE_URL,
// Public (client + server)
public: {
apiBase: process.env.API_BASE || 'https://api.example.com',
appName: 'My App'
}
},
// App config
app: {
head: {
title: 'My Nuxt App',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
]
}
},
// Nitro config (server)
nitro: {
preset: 'cloudflare-pages'
},
// TypeScript
typescript: {
strict: true,
typeCheck: true
}
})typescript
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
}
})Runtime Config Usage
运行时配置使用方式
typescript
// In composables or components
const config = useRuntimeConfig()
// Public values (client + server)
const apiBase = config.public.apiBase
// Server-only values (only in server/)
const apiSecret = config.apiSecret // undefined on client!Critical Rule: Always use instead of for environment variables in production.
useRuntimeConfig()process.envtypescript
// 在可组合函数或组件中
const config = useRuntimeConfig()
// 公开值(客户端 + 服务端)
const apiBase = config.public.apiBase
// 仅服务端可用的值(仅在 server/ 目录中)
const apiSecret = config.apiSecret // 在客户端中为 undefined!重要规则:在生产环境中,始终使用 而非 来获取环境变量。
useRuntimeConfig()process.envApp Config vs Runtime Config
App Config 与 Runtime Config 对比
| Feature | App Config | Runtime Config |
|---|---|---|
| Location | | |
| Hot reload | Yes | No |
| Secrets | No | Yes (server-only) |
| Use case | UI settings, themes | API keys, URLs |
typescript
// app/app.config.ts - UI settings (hot-reloadable)
export default defineAppConfig({
theme: {
primaryColor: '#3490dc'
},
ui: {
rounded: 'lg'
}
})
// Usage
const appConfig = useAppConfig()
const color = appConfig.theme.primaryColor| 特性 | App Config | Runtime Config |
|---|---|---|
| 位置 | | |
| 热重载 | 支持 | 不支持 |
| 存储机密 | 不可以 | 可以(仅服务端) |
| 使用场景 | UI 设置、主题 | API 密钥、URL |
typescript
// app/app.config.ts - UI 设置(支持热重载)
export default defineAppConfig({
theme: {
primaryColor: '#3490dc'
},
ui: {
rounded: 'lg'
}
})
// 使用方式
const appConfig = useAppConfig()
const color = appConfig.theme.primaryColorRouting
路由
File-Based Routing
基于文件的路由
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/* (catch-all)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/*(通配符路由)Dynamic Routes
动态路由
vue
<!-- app/pages/users/[id].vue -->
<script setup lang="ts">
const route = useRoute()
// Get route params
const userId = route.params.id
// Reactive (updates when route changes)
const userId = computed(() => route.params.id)
// Fetch user data
const { data: user } = await useFetch(`/api/users/${userId.value}`)
</script>
<template>
<div>
<h1>{{ user?.name }}</h1>
</div>
</template>vue
<!-- 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>Navigation
导航
vue
<script setup>
const goToUser = (id: string) => {
navigateTo(`/users/${id}`)
}
const goBack = () => {
navigateTo(-1) // Go back in history
}
// With options
const goToLogin = () => {
navigateTo('/login', {
replace: true, // Replace current history entry
external: false // Internal navigation
})
}
</script>
<template>
<!-- Declarative navigation -->
<NuxtLink to="/about">About</NuxtLink>
<NuxtLink :to="`/users/${user.id}`">View User</NuxtLink>
<!-- Prefetching (default: on hover) -->
<NuxtLink to="/dashboard" prefetch>Dashboard</NuxtLink>
<!-- No prefetch -->
<NuxtLink to="/admin" :prefetch="false">Admin</NuxtLink>
</template>vue
<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>Route Middleware
路由中间件
typescript
// app/middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
return navigateTo('/login')
}
})vue
<!-- app/pages/dashboard.vue -->
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
</script>typescript
// app/middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
return navigateTo('/login')
}
})vue
<!-- app/pages/dashboard.vue -->
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
</script>Global Middleware
全局中间件
typescript
// app/middleware/analytics.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// Runs on every route change
if (import.meta.client) {
window.gtag?.('event', 'page_view', {
page_path: to.path
})
}
})typescript
// app/middleware/analytics.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// 在每次路由变化时运行
if (import.meta.client) {
window.gtag?.('event', 'page_view', {
page_path: to.path
})
}
})Page Meta
页面元数据
vue
<script setup lang="ts">
definePageMeta({
title: 'Dashboard',
middleware: ['auth'],
layout: 'admin',
pageTransition: { name: 'fade' },
keepalive: true
})
</script>vue
<script setup lang="ts">
definePageMeta({
title: '控制台',
middleware: ['auth'],
layout: 'admin',
pageTransition: { name: 'fade' },
keepalive: true
})
</script>SEO & Meta Tags
SEO 与元标签
useSeoMeta (Recommended)
useSeoMeta(推荐使用)
vue
<script setup lang="ts">
useSeoMeta({
title: 'My Page Title',
description: 'Page description for search engines',
ogTitle: 'My Page Title',
ogDescription: 'Page description',
ogImage: 'https://example.com/og-image.jpg',
ogUrl: 'https://example.com/my-page',
twitterCard: 'summary_large_image',
twitterTitle: 'My Page Title',
twitterDescription: 'Page description',
twitterImage: 'https://example.com/og-image.jpg'
})
</script>vue
<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 (More Control)
useHead(更多自定义控制)
vue
<script setup lang="ts">
useHead({
title: 'My Page Title',
meta: [
{ name: 'description', content: 'Page description' },
{ property: 'og:title', content: 'My Page Title' }
],
link: [
{ rel: 'canonical', href: 'https://example.com/my-page' }
],
script: [
{ src: 'https://example.com/script.js', defer: true }
]
})
</script>vue
<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>Dynamic Meta Tags
动态元标签
vue
<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>vue
<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>Title Template
标题模板
typescript
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
titleTemplate: '%s | My App' // "Page Title | My App"
}
}
})typescript
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
titleTemplate: '%s | 我的应用' // 最终效果:"页面标题 | 我的应用"
}
}
})Error Handling
错误处理
Error Page
错误页面
vue
<!-- 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">Go Home</button>
</div>
</template>vue
<!-- 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>Error Boundaries (Component-Level)
错误边界(组件级)
vue
<template>
<NuxtErrorBoundary @error="handleError">
<template #error="{ error, clearError }">
<div class="error-container">
<h2>Something went wrong</h2>
<p>{{ error.message }}</p>
<button @click="clearError">Try again</button>
</div>
</template>
<!-- Your component content -->
<MyComponent />
</NuxtErrorBoundary>
</template>
<script setup>
const handleError = (error: Error) => {
console.error('Component error:', error)
// Send to error tracking service
}
</script>vue
<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>Throwing Errors
抛出错误
typescript
// In pages or components
throw createError({
statusCode: 404,
statusMessage: 'Page Not Found',
fatal: true // Shows error page, stops rendering
})
// Non-fatal error (shows inline)
throw createError({
statusCode: 400,
message: 'Invalid input'
})typescript
// 在页面或组件中
throw createError({
statusCode: 404,
statusMessage: '页面未找到',
fatal: true // 显示错误页面,停止渲染
})
// 非致命错误(内联显示)
throw createError({
statusCode: 400,
message: '输入无效'
})API Error Handling
API 错误处理
typescript
const { data, error } = await useFetch('/api/users')
if (error.value) {
// Handle error gracefully
showError({
statusCode: error.value.statusCode,
message: error.value.message
})
}typescript
const { data, error } = await useFetch('/api/users')
if (error.value) {
// 优雅处理错误
showError({
statusCode: error.value.statusCode,
message: error.value.message
})
}Common Anti-Patterns
常见反模式
Using process.env Instead of Runtime Config
使用 process.env 而非 Runtime Config
typescript
// WRONG - Won't work in production!
const apiUrl = process.env.API_URL
// CORRECT
const config = useRuntimeConfig()
const apiUrl = config.public.apiBasetypescript
// 错误写法 - 生产环境中无法正常工作!
const apiUrl = process.env.API_URL
// 正确写法
const config = useRuntimeConfig()
const apiUrl = config.public.apiBaseMissing Middleware Guards
缺少中间件守卫返回
typescript
// WRONG - No return, middleware continues
export default defineNuxtRouteMiddleware((to) => {
const { isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
navigateTo('/login') // Missing return!
}
})
// CORRECT
export default defineNuxtRouteMiddleware((to) => {
const { isAuthenticated } = useAuth()
if (!isAuthenticated.value) {
return navigateTo('/login') // Return stops middleware chain
}
})typescript
// 错误写法 - 没有返回值,中间件会继续执行
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') // 返回值会终止中间件链
}
})Non-Reactive Route Params
非响应式的路由参数
typescript
// WRONG - Not reactive
const userId = route.params.id
// CORRECT - Reactive
const userId = computed(() => route.params.id)typescript
// 错误写法 - 非响应式
const userId = route.params.id
// 正确写法 - 响应式
const userId = computed(() => route.params.id)Troubleshooting
故障排除
Build Errors / Type Errors:
bash
rm -rf .nuxt .output node_modules/.vite && bun install && bun run devRoute Not Found:
- Check file is in (not root
app/pages/)pages/ - Verify file extension is
.vue - Check for typos in dynamic params
[id].vue
Middleware Not Running:
- Ensure file has suffix for global middleware
.global.ts - Check matches filename
definePageMeta({ middleware: 'name' }) - Verify middleware returns or nothing
navigateTo()
Meta Tags Not Updating:
- Use reactive values:
title: () => post.value?.title - Ensure is called in
useSeoMeta<script setup>
构建错误 / 类型错误:
bash
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>
Related Skills
相关技能
- nuxt-data: Composables, data fetching, state management
- nuxt-server: Server routes, API patterns, database integration
- nuxt-production: Performance, testing, deployment
- nuxt-ui-v4: Nuxt UI component library
- nuxt-data:可组合函数、数据获取、状态管理
- nuxt-server:服务端路由、API 模式、数据库集成
- nuxt-production:性能优化、测试、部署
- nuxt-ui-v4:Nuxt UI 组件库
Templates Available
可用模板
See directory for:
templates/- Production-ready
nuxt.config.ts - with proper structure
app.vue - Middleware examples
Version: 4.0.0 | Last Updated: 2025-12-28 | License: MIT
查看 目录获取:
templates/- 生产就绪的
nuxt.config.ts - 结构规范的
app.vue - 中间件示例
版本:4.0.0 | 最后更新:2025-12-28 | 许可证:MIT