Nuxt 4 核心特性与开发实践
记录 Nuxt 4 的核心特性与开发实践,包括架构设计、渲染策略、组件模式等内容。
概述
Nuxt 4 在 2025 年正式发布,带来了若干架构层面的改进。本文记录了使用 Nuxt 4 构建企业级官网过程中的一些实践经验和思考。
Nuxt 4 的关键变化
应用目录结构
Nuxt 4 将前端代码统一到 app/ 目录下,这是与 Nuxt 3 的重要区别:
nuxt-project/
├── app/ # 应用目录
│ ├── app.vue # 根组件
│ ├── app.config.ts # 应用配置
│ ├── components/ # Vue 组件
│ ├── composables/ # 组合式函数
│ ├── layouts/ # 布局组件
│ ├── pages/ # 页面路由
│ ├── plugins/ # 插件
│ └── utils/ # 工具函数
├── content/ # Nuxt Content 内容
├── server/ # 服务端代码
│ ├── api/ # API 路由
│ └── utils/ # 服务端工具
├── public/ # 静态资源
└── nuxt.config.ts # Nuxt 配置这种结构让前后端代码边界更加清晰。
兼容性日期
Nuxt 4 引入了 compatibilityDate 配置项,用于控制版本兼容性:
// nuxt.config.ts
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: {
enabled: process.env.NODE_ENV === 'development'
},
typescript: {
strict: true
}
})模块配置
模块注册
一个典型的企业级项目通常需要集成多个 Nuxt 模块:
// nuxt.config.ts
const studioEnabled = process.env.NUXT_STUDIO === 'true'
export default defineNuxtConfig({
modules: [
'@nuxt/fonts', // 字体管理
'@nuxt/content', // 内容管理
studioEnabled ? 'nuxt-studio' : undefined, // 条件加载
'@nuxt/image', // 图片优化
'@nuxtjs/i18n', // 国际化
'@nuxt/ui', // UI 组件库
'@nuxt/icon', // 图标系统
'@formkit/auto-animate/nuxt', // 动画
'@nuxtjs/seo' // SEO 优化
].filter(Boolean)
})条件加载模块是一个实用技巧。例如 nuxt-studio 在某些开发环境下可能有兼容性问题,通过环境变量控制仅在需要时加载。
常用模块列表
| 模块 | 用途 | 文档 |
|---|---|---|
| @nuxt/content | Markdown 内容管理 | https://content.nuxt.com |
| @nuxt/image | 图片优化 | https://image.nuxt.com |
| @nuxt/ui | UI 组件库 | https://ui.nuxt.com |
| @nuxtjs/i18n | 国际化 | https://i18n.nuxtjs.org |
| @nuxtjs/seo | SEO 优化 | https://seo.nuxtjs.org |
| nuxt-studio | 可视化编辑 | https://nuxt.studio |
更多模块可在 Nuxt Modules 查找。
渲染策略
Nuxt 4 支持多种渲染模式,理解它们的差异对于构建高性能应用很重要。
预渲染(Prerendering)
预渲染在构建时生成静态 HTML,适合内容相对固定的页面:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
'/about': { prerender: true },
'/sponsors': { prerender: true }
}
})预渲染的优势:
- 静态文件直接返回,无需服务端计算
- 可缓存于 CDN 边缘节点
- 不依赖数据库或外部服务
ISR(增量静态再生)
ISR 是预渲染和动态渲染的平衡,适合内容定期更新的场景:
routeRules: {
// 新闻列表:1 小时缓存
'/news': process.env.NODE_ENV === 'development'
? {}
: { swr: 3600 },
'/news/**': process.env.NODE_ENV === 'development'
? {}
: { swr: 3600 },
// API 路由缓存
'/api/news': { swr: 1800 }, // 30 分钟
'/api/cars': { swr: 7200 }, // 2 小时
}ISR 的工作流程:
- 首次请求时,服务端渲染页面并缓存
- 在 swr 指定的时间内,直接返回缓存内容
- 缓存过期后,下一次请求仍返回旧缓存,同时在后台重新渲染
- 后台渲染完成后,更新缓存供后续请求使用
注意:开发环境下应禁用 ISR,否则调试时可能命中陈旧缓存,导致修改不生效。
预渲染配置注意事项
当使用 Nuxt Content v3 时,预渲染配置需要注意:
nitro: {
prerender: {
concurrency: 1, // 强制串行处理
failOnError: true,
crawlLinks: true,
ignore: ['/_ipx/**'] // 排除动态图片路由
}
}concurrency: 1 强制串行预渲染,这是因为 Nuxt Content v3 使用 SQLite 作为底层存储,多进程同时访问 SQLite 可能导致内存指针错误。
组件架构
全局组件注册
Nuxt 支持自动导入组件,通过配置可以实现不同的注册策略:
// nuxt.config.ts
export default defineNuxtConfig({
components: [
{
path: '~/components/content',
global: true // 全局注册
},
'~/components' // 按需导入
]
})Composables 模式
Composables 是 Vue 3 组合式 API 的核心概念,Nuxt 提供了 auto-imports 机制:
// app/composables/useTheme.ts
export const useTheme = () => {
const currentTheme = ref<'light' | 'dark'>('dark')
const setTheme = (theme: 'light' | 'dark') => {
currentTheme.value = theme
document.documentElement.setAttribute('data-theme', theme)
localStorage.setItem('theme', theme)
if (theme === 'dark') {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}
const toggleTheme = () => {
setTheme(currentTheme.value === 'dark' ? 'light' : 'dark')
}
const initTheme = () => {
const saved = localStorage.getItem('theme') as 'light' | 'dark' | null
setTheme(saved || 'dark')
}
return {
currentTheme: readonly(currentTheme),
setTheme,
toggleTheme,
initTheme
}
}使用时无需导入:
<script setup lang="ts">
const { currentTheme, toggleTheme, initTheme } = useTheme()
onMounted(() => {
initTheme()
})
</script>防止主题闪烁
主题切换时,如果等 JavaScript 加载后再应用主题,用户会看到短暂的样式闪烁。解决方案是在 <head> 中注入内联脚本:
// nuxt.config.ts
app: {
head: {
script: [
{
innerHTML: `(function(){
var d = document.documentElement;
try {
var t = localStorage.getItem('theme') || 'dark';
d.setAttribute('data-theme', t);
if (t === 'dark') d.classList.add('dark');
} catch(e) {}
})()`,
type: 'text/javascript',
tagPosition: 'head'
}
]
}
}这段代码在 HTML 解析时立即执行,确保首屏渲染时主题已经正确设置。
服务端 API
API 路由定义
Nuxt 的 server/api/ 目录下可以定义 API 路由:
// server/api/news.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event)
const category = query.category as string | undefined
const search = (query.search as string)?.trim().toLowerCase()
const page = Math.max(1, Number(query.page) || 1)
const pageSize = Math.min(50, Math.max(1, Number(query.pageSize) || 10))
// 获取数据...
const data = await fetchData(category, search, page, pageSize)
return {
data: data.items,
total: data.total,
page,
pageSize
}
})前端调用
使用 Nuxt 提供的 useFetch 或 useAsyncData:
<script setup lang="ts">
const currentPage = ref(1)
const itemsPerPage = ref(9)
const selectedCategory = ref('all')
const searchQuery = ref('')
const { data, status, refresh } = await useAsyncData('news-list',
() => $fetch('/api/news', {
query: {
page: currentPage.value,
pageSize: itemsPerPage.value,
category: selectedCategory.value,
search: searchQuery.value
}
}),
{
watch: [currentPage, itemsPerPage, selectedCategory, searchQuery]
}
)
</script>watch 选项让任何依赖变化时自动重新获取数据。
国际化
配置 @nuxtjs/i18n
// nuxt.config.ts
i18n: {
locales: [
{ code: 'en', file: 'en.json', name: 'English' },
{ code: 'zh', file: 'zh.json', name: '简体中文' }
],
defaultLocale: 'zh',
strategy: 'prefix_except_default',
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
fallbackLocale: 'zh'
}
}strategy: 'prefix_except_default' 表示默认语言不添加 URL 前缀,其他语言路由以对应前缀开头。
使用翻译
<template>
<h1>{{ t('heroTitle') }}</h1>
<p>{{ t('heroDesc') }}</p>
</template>
<script setup lang="ts">
const { t } = useI18n()
</script>SEO 配置
使用 @nuxtjs/seo
// nuxt.config.ts
site: {
url: 'https://example.com',
name: 'Site Name',
description: 'Site description',
defaultLocale: 'zh'
},
sitemap: {
zeroRuntime: true
},
robots: {
allow: '/',
sitemap: 'https://example.com/sitemap.xml'
}页面级 SEO
<script setup lang="ts">
useHead({
title: () => t('pageTitle')
})
useSeoMeta({
description: () => t('pageDescription'),
ogTitle: () => t('pageTitle'),
ogDescription: () => t('pageDescription'),
ogImage: 'https://example.com/cover.jpg'
})
</script>小结
Nuxt 4 提供了完整的全栈开发能力,合理的架构设计是项目可维护性的基础。渲染策略的选择应根据页面特性决定:静态内容适合预渲染,动态内容适合 ISR 或 SSR。Composables 模式和自动导入机制让代码组织更加清晰。
参考资料:
- 上一篇:Nuxt 性能优化
- 下一篇:Nuxt CI/CD 部署