Article

全栈框架 Nuxt.js

更新于:2026-07-10

第一部分:基础入门

第一章:Nuxt 4 概述与核心优势

1.1 什么是 Nuxt?与 Vue 的关系

概念名称说明注意事项
Nuxt.js基于 Vue.js 的全栈框架,提供开箱即用的 SSR(服务端渲染)、静态站点生成(SSG)、自动路由、状态管理等能力,简化 Vue 应用的工程化开发。Nuxt 不是 Vue 的替代品,而是其上层封装,依赖 Vue 核心库运行。
Vue.js渐进式 JavaScript 框架,用于构建用户界面。核心关注视图层,支持组件化开发。Vue 提供响应式系统和组件模型,但不包含路由、SSR、构建工具等生产级功能。
关系定位Nuxt = Vue + 路由 + 状态管理 + 构建工具 + 服务端引擎 + 最佳实践约定。开发者可专注于业务逻辑,无需手动配置 Webpack、Vite、Vue Router 等。使用 Nuxt 时仍需掌握 Vue 基础(如 ref、reactive、生命周期),但无需显式安装 vue-router 或 pinia(除非自定义)。

1.2 Nuxt 4 的核心特性(SSR、自动导入、文件路由等)

特性名称说明注意事项
服务端渲染(SSR)页面在服务器端预渲染为 HTML,提升首屏加载速度与 SEO。Nuxt 4 默认启用混合渲染(Hybrid Rendering),可按路由选择 SSG/SSR/CSR。需确保服务端环境支持 Node.js;敏感数据不应在 SSR 中直接暴露。
自动导入(Auto Imports)自动扫描 composables/、components/、utils/ 等目录,无需手动 import 即可在任意组件或页面中使用。仅限项目内符合命名规范的函数/组件;第三方库需通过插件或 nuxt.config 显式配置。
文件路由系统基于 app/pages/ 目录结构自动生成 Vue Router 路由配置,支持动态路由([id].vue)、嵌套路由(目录嵌套)等。文件名必须以 .vue 结尾;非页面组件应放在 components/ 或使用下划线前缀(如 _Card.vue)避免被识别为路由。
Nitro 服务端引擎Nuxt 4 内置新一代服务端引擎 Nitro,统一 API 路由、中间件、部署目标(支持 Serverless、Node.js、Deno 等)。所有服务端逻辑(API、中间件)必须放在 server/ 目录下;Nitro 在构建时自动打包为独立服务。
组合式 API 优先全面采用 Vue 3 的 Composition API(如 setup()、ref、computed),并提供 Nuxt 专属组合函数(如 useAsyncData)。Options API 仍可用,但官方推荐使用组合式风格以获得更好的类型推导和逻辑复用。

1.3 约定优于配置:Nuxt 的设计哲学

概念名称说明注意事项
约定优于配置(Convention over Configuration)Nuxt 通过预设目录结构和命名规则(如 pages/ 表示路由、layouts/ 表示布局)减少开发者配置负担,提升开发效率。开发者应优先遵循默认约定;若需自定义(如修改 pages 目录),需在 nuxt.config.ts 中显式声明。
零配置启动新项目无需配置 Webpack、Babel、TypeScript 编译器等即可运行,内置 Vite 构建工具。高级需求(如自定义 loader)仍可通过 nuxt.config.ts 扩展,但应尽量避免破坏默认约定。
自动化工程能力包括热更新、错误提示、类型检查、代码分割、资源优化等均由框架自动处理。这些能力依赖于 Nuxt 的内部工具链(如 unplugin-vue-components、nitropack),升级时需注意兼容性。
可扩展但不强制虽然强调约定,但 Nuxt 允许通过模块(Modules)、插件(Plugins)、钩子(Hooks)进行深度定制。过度自定义可能导致项目难以维护或升级;建议优先使用官方模块(如 @nuxtjs/tailwindcss)。

1.4 Nuxt 4 相比 Nuxt 3 的关键改进

改进项说明注意事项
更快的冷启动与 HMR基于 Vite 5 和 Nitro 2,开发服务器启动速度提升 30%+,热更新更稳定。需 Node.js ≥ 18;旧版 Node 可能导致兼容问题。
更严格的类型安全完整 TypeScript 支持,包括 API 路由、composables、组件 props 的自动类型推导。推荐使用 definePageMeta、defineProps 等宏以获得最佳类型体验。
改进的混合渲染(Hybrid Rendering)支持在同一项目中为不同路由指定渲染模式(SSG / SSR / CSR),通过 routeRules 配置。静态路由(SSG)需在构建时确定;动态路由建议使用 SSR 或 CSR。
更小的客户端包体积通过 Tree-shaking 和自动代码分割,减少未使用代码的打包体积。自动导入机制已优化,避免全局污染;但仍需注意第三方库的副作用引入。
更好的模块生态系统官方模块全面适配 Nuxt 4,社区模块迁移加速;支持 ESM 优先的现代包格式。使用第三方模块前应确认其是否标注支持 Nuxt 4(查看 package.json 中的 nuxt 字段)。
开发者体验增强内置 Nuxt DevTools(可视化组件树、路由、状态)、更好的错误堆栈、VS Code 插件集成。DevTools 默认仅在开发环境启用;生产环境自动移除,不影响性能。

第二章:项目初始化与开发环境搭建

2.1 环境要求(Node.js、编辑器、WSL 建议)

要求项说明注意事项
Node.js 版本Nuxt 4 要求 Node.js ≥ 18.0.0(推荐 18.x 或 20.x LTS)。Nitro 引擎依赖现代 ES 模块和 Web APIs。使用 node -v 验证版本;低于 18 将导致构建失败或运行时错误。
包管理器支持 npm、yarn、pnpm、bun。官方推荐 pnpm(因高效依赖解析和磁盘节省)。若使用 pnpm,需确保全局安装:npm install -g pnpm
代码编辑器推荐 VS Code,配合官方扩展 Nuxt VS Code Extension(提供语法高亮、组件自动补全、DevTools 集成)。安装后重启编辑器以激活 Nuxt 专属功能(如 <NuxtLayout> 智能提示)。
操作系统Windows、macOS、Linux 均支持。Windows 用户建议启用 WSL2(Windows Subsystem for Linux)以获得类 Unix 开发体验。WSL2 可避免路径分隔符、文件监听等兼容性问题;Docker 开发也更顺畅。
网络环境需能访问 npm registry(或配置镜像源如 https://registry.npmmirror.com)。国内用户可设置 .npmrc 或使用 --registry 参数加速依赖安装。

2.2 使用 nuxi 创建 Nuxt 4 项目

操作步骤名称操作细节注意事项
安装 nuxi(可选)nuxi 是 Nuxt 官方 CLI 工具,通常无需全局安装,可通过 npm create nuxt@latest 直接调用。全局安装命令为 npm install -g nuxi,但不推荐,因项目应锁定 nuxi 版本。
创建新项目在终端执行:npm create nuxt@latest my-nuxt-app,项目名 my-nuxt-app 可自定义;确保目标目录不存在或为空。按交互提示选择 TypeScript、ESLint、Tailwind CSS 等选项。
选择模板特性交互式选项包括:TypeScript(默认开启)、ESLint / Prettier、Tailwind CSS、Nuxt DevTools、SSR/SSG 渲染模式。建议初学者启用所有开发辅助工具;生产项目按需选择。
安装依赖创建完成后,进入目录并自动安装依赖(若未自动安装,手动运行 npm install 或对应包管理器命令)。若使用 pnpm,命令为 pnpm install;bun 用户用 bun install
验证项目结构成功创建后,目录应包含 app/、server/、nuxt.config.ts、package.json 等核心文件。若缺少 app/ 目录,可能误选了旧版模板(确保使用 nuxt@latest)。

2.3 项目目录结构详解(app/、server/、public/ 等)

目录/文件用途说明注意事项
app/应用主目录,包含页面、布局、根组件等前端逻辑。所有 Vue 页面必须放在 app/pages/ 下;app.vue 是应用根组件。
app/pages/基于文件的路由系统目录。每个 .vue 文件对应一个路由(如 index.vue → /)。动态路由使用 [param].vue;嵌套路由通过子目录实现。
app/layouts/布局组件目录。默认布局为 default.vue,可通过 definePageMeta({ layout: 'custom' }) 切换。布局组件必须包含 <slot /> 以渲染页面内容。
app/components/全局组件目录。所有 .vue 组件自动注册,可在任意页面直接使用(无需 import)。非页面组件建议放在此处;避免与 pages/ 混淆。
server/服务端逻辑目录,由 Nitro 引擎处理。包含 API 路由、中间件、工具函数等。此目录代码仅在服务端运行,不可引用 Vue 组件或浏览器 API。
server/api/API 路由目录。每个文件暴露一个事件处理函数(如 hello.get.ts → GET /api/hello)。文件名决定路由路径;支持 .ts、.js、.mjs。
public/静态资源目录。文件直接复制到构建输出根目录(如 public/favicon.ico → /favicon.ico)。不经过构建处理;适合图标、robots.txt、验证文件等。
assets/需要构建处理的静态资源(如图片、字体、CSS)。通过 ~/assets/ 引用。支持 SCSS、TypeScript 等预处理器;体积过大建议移至 CDN。
nuxt.config.ts项目配置文件。用于自定义构建、模块、运行时配置等。使用 defineNuxtConfig() 包裹配置对象以获得类型提示。
composables/组合函数目录。所有函数自动导入,命名需符合驼峰规范(如 useCounter.ts → useCounter())。仅限组合式逻辑;避免副作用或全局状态污染。

2.4 启动开发服务器与使用 Nuxt DevTools

操作步骤名称操作细节注意事项
启动开发服务器在项目根目录运行:npm run dev(或对应包管理器命令,如 pnpm dev),默认监听 http://localhost:3000;端口冲突时自动递增(3001、3002…)。
访问应用浏览器打开 http://localhost:3000 查看首页(通常为 app/pages/index.vue 内容)。首次启动可能较慢(需编译依赖);后续热更新极快。
启用 Nuxt DevTools确保创建项目时启用了 DevTools(或手动安装 @nuxt/devtools 模块)。开发时按 Ctrl+Shift+D(Windows/Linux)或 Cmd+Shift+D(macOS)呼出面板。DevTools 仅在开发环境可用;生产构建自动剥离。
DevTools 核心功能组件树查看与 props 检查、路由列表与跳转测试、状态管理(useState)监控、网络请求(useFetch)日志。需使用 Composition API 编写组件才能完整显示响应式数据。
自定义 DevTools 行为在 nuxt.config.ts 中配置:devtools: { enabled: true, vscode: {} }可关闭 DevTools(设 enabled: false)或配置 VS Code 集成。
热模块替换(HMR)修改 .vue、.ts 文件后,浏览器自动更新,状态保留(如表单输入、计数器值)。若 HMR 失效,检查是否修改了 nuxt.config.ts(需重启服务器)。

第三章:应用入口与页面系统

3.1 app.vue:应用根组件的作用与写法

概念/方法说明注意事项
app.vue 文件位置位于项目根目录下(与 nuxt.config.ts 同级),是整个 Nuxt 应用的根组件。必须存在;若缺失,Nuxt 会自动生成一个空 <NuxtPage /> 组件。
核心作用包裹所有页面内容,可定义全局布局结构(如 Header/Footer)、全局状态、错误边界等。不应包含业务逻辑;复杂布局应委托给 layouts/。
基本写法示例<template><div class="app"><header>Global Header</header><NuxtPage /><footer>Global Footer</footer></div></template>必须包含 <NuxtPage /> 组件,否则页面内容不会渲染。
使用组合式 API可在 <script setup> 中使用 useState、useAsyncData 等 Nuxt 组合函数。避免在此处发起高成本数据请求;会影响所有页面加载性能。
全局样式注入可在 <style> 标签中定义全局 CSS,或通过 @import 引入外部样式文件。推荐将全局样式放在 assets/css/global.css 并在 nuxt.config.ts 中注册。

3.2 基于文件的路由系统(app/pages/)

概念/规则说明注意事项
路由映射规则app/pages/index.vue → /;app/pages/about.vue → /about;app/pages/products/list.vue → /products/list文件名决定路由路径;目录结构即路由层级。
页面组件要求必须为 .vue 单文件组件,且导出默认 Vue 组件对象(可通过 <script setup> 或 export default)。非 .vue 文件(如 .ts)不会被识别为页面。
自动路由生成Nuxt 在构建时扫描 app/pages/ 目录,自动生成 Vue Router 配置,无需手动编写 createRouter。修改页面文件后,开发服务器自动更新路由(HMR 支持)。
路由优先级同级目录下,静态路径优先于动态路径(如 user.vue 优先于 [id].vue)。避免命名冲突;明确区分静态页与参数页。
首页约定app/pages/index.vue 是默认首页,对应根路径 /。若删除此文件,访问 / 将返回 404(除非配置 fallback)。

3.3 动态路由与嵌套路由

路由类型文件命名方式对应路径示例注意事项
动态路由(单参数)app/pages/user/[id].vue/user/123参数通过 useRoute().params.id 获取;参数名必须与方括号内一致。
动态路由(多参数)app/pages/post/[category]/[slug].vue/post/news/hello-world多层嵌套需逐级创建目录;参数按路径顺序匹配。
可选动态参数app/pages/search/[[query]].vue/search 或 /search/vue使用双中括号 [[ ]] 表示参数可选;未提供时值为 undefined。
嵌套路由(父-子)父:app/pages/settings.vue,子:app/pages/settings/profile.vue/settings(父),/settings/profile(子)父页面必须包含 <NuxtPage /> 才能渲染子页面。
嵌套布局复用嵌套路由自动继承父级布局(除非子页面显式指定新布局)。可通过 definePageMeta({ layout: false }) 禁用布局。
catch-all 路由app/pages/[…slug].vue匹配任意深度路径(如 /a/b/c)用于自定义 404 或 CMS 类路由;参数为数组 ['a', 'b', 'c']

3.4 页面级组件的组织与非页面化配置

场景解决方案说明注意事项
避免组件被识别为页面将非页面组件放入 app/components/ 目录此目录下所有 .vue 文件自动注册为全局组件,不参与路由生成。推荐命名清晰(如 UserCard.vue),避免与页面名冲突。
临时禁用页面路由在 app/pages/ 中使用下划线前缀命名文件,如 _draft.vueNuxt 忽略以下划线 _ 开头的文件,不生成对应路由。适用于草稿、废弃页面;仍可通过 import 手动使用组件。
条件性排除页面使用 nuxt.config.ts 中的 ignore 选项ignore: ['**/pages/_*.vue']适用于批量忽略;但不如下划线命名直观。
页面专属组件共存在页面同级目录创建子目录存放辅助组件,如 app/pages/user/Avatar.vue该组件仅在 user.vue 中使用,且不会成为独立路由。需手动 import 使用(因不在 components/ 目录,不自动导入)。
使用 <ClientOnly> 包裹对含浏览器 API 的组件包裹 <ClientOnly>防止 SSR 报错(如 window、localStorage 访问)。仅解决渲染问题;数据获取仍需在 onMounted 中处理。

第二部分:核心功能开发

第四章:组件系统与自动导入

4.1 全局组件自动导入机制

概念/机制说明注意事项
自动扫描目录Nuxt 默认扫描 app/components/ 目录下的所有 .vue、.ts、.js 文件(支持子目录)。仅限项目根目录下的 app/components/;不包括 node_modules 或其他路径。
自动注册规则组件文件名(PascalCase)即为组件名。例如 MyButton.vue → <MyButton />文件名必须符合 Vue 组件命名规范(首字母大写,避免 kebab-case 作为标签名)。
无需手动 import在任意页面、布局或组件中可直接使用已注册组件,无需 import 语句。若组件未生效,检查文件扩展名是否为 .vue,以及是否位于正确目录。
支持组合函数自动导入composables/ 目录下的函数(如 useCounter.ts)也自动导入,调用方式为 useCounter()。函数名必须以 use 开头,且导出默认函数(export default () => {})。
类型推导支持VS Code 配合 Volar/Nuxt 插件可自动提供组件 props 和事件的类型提示。需在组件中使用 defineProps、defineEmits 宏以启用完整类型检查。

4.2 页面专属组件的组织方式(避免被识别为页面)

场景推荐做法说明注意事项
页面内私有组件将组件文件放在 app/pages/ 下的子目录中,如 app/pages/user/Avatar.vue该组件仅用于 user.vue 页面,不会生成路由。必须手动 import Avatar from './Avatar.vue' 使用(因不在 components/,不自动导入)。
临时草稿组件使用下划线前缀命名:_ModalDraft.vueNuxt 忽略以下划线 _ 开头的 .vue 文件,不注册为路由或全局组件。适用于开发中未完成的组件;仍可通过相对路径 import 使用。
共享但非全局组件放入 app/components/ 子目录(如 app/components/ui/Button.vue)仍自动导入,组件名为 UiButton(目录名+文件名转 PascalCase)。避免扁平化命名冲突;适合按功能模块组织组件。
条件性排除在 nuxt.config.ts 中配置 components: { dirs: [...] } 显式指定扫描路径可完全跳过 pages/ 目录中的组件扫描。一般不推荐;优先使用目录结构或命名约定控制。
使用 <script setup> 局部注册在页面组件内部直接定义子组件(较少用)<script setup>import LocalCard from './LocalCard.vue'</script>仅适用于极简复用;破坏自动导入优势,不推荐常规使用。

4.3 自定义自动导入目录配置(components/ 扩展)

配置项语法示例用途注意事项
扩展 components 目录export default defineNuxtConfig({ components: [ '~/components', '~/lib/custom-ui' ] })将 ~/lib/custom-ui 中的组件也纳入自动导入范围。路径需以 ~ 或相对路径开头;支持多个目录。
自定义组件前缀components: [{ path: '~/components/base', prefix: 'Base' }]base/Button.vue → <BaseButton />避免命名冲突;适合设计系统组件库。
禁用自动导入components: false完全关闭自动导入功能,需手动 import 所有组件。仅适用于特殊迁移或调试场景;大幅降低开发效率。
控制扫描深度components: [{ path: '~/components', extensions: ['vue', 'ts'] }]限制仅扫描 .vue 和 .ts 文件。默认已包含常见扩展;显式声明可提升构建性能。
全局 vs 局部作用域所有通过 components 配置的目录均为全局作用域组件无法实现”仅在某布局下可用”的局部自动导入。如需作用域限制,应手动 import 或使用插槽传递。

4.4 组件命名规范与类型提示支持

规范项推荐规则说明注意事项
文件命名使用 PascalCase(如 UserProfile.vue)与 Vue 官方风格指南一致;确保组件标签 <UserProfile /> 符合 HTML 自定义元素规范。避免 kebab-case(如 user-profile.vue),虽可工作但标签需转为 <UserProfile />
组件标签使用在模板中始终使用 PascalCase 标签<template><UserProfile /></template>Vue 3 支持 kebab-case 标签(<user-profile />),但 Nuxt 自动导入仅保证 PascalCase 可靠。
Props 类型定义使用 defineProps<{ name: string }>()(TypeScript)启用严格的 props 类型检查和 IDE 提示。避免使用 props: { name: String }(Options API 风格),不利于类型推导。
Emits 类型定义使用 const emit = defineEmits<{ (e: 'submit'): void }>()确保 $emit('submit') 被类型系统校验。事件名应为字面量类型,避免字符串变量导致类型丢失。
自动类型生成Nuxt 在 .nuxt/ 目录下生成 components.d.ts,为所有自动导入组件提供全局类型声明。无需手动编写 .d.ts 文件;重启 dev server 可刷新类型。若类型未更新,删除 .nuxt/ 并重新启动开发服务器。
第三方组件集成通过插件或模块注册的第三方组件(如 VueFinalModal)需手动声明类型或使用 globalComponents 配置。自动导入仅适用于本地项目组件;外部库需额外配置。可在 nuxt.config.ts 中添加 typescript: { shim: false } 精简类型。

第五章:布局与插槽系统

5.1 app/layouts/ 目录与默认布局

概念/文件说明注意事项
app/layouts/ 目录存放所有布局组件(.vue 文件),每个文件对应一种页面布局结构。必须位于 app/ 下;不在此目录的组件不会被识别为布局。
默认布局文件app/layouts/default.vue 是 Nuxt 自动应用的默认布局(若未指定其他布局)。若该文件不存在,Nuxt 会隐式使用 <NuxtLayout><NuxtPage /></NuxtLayout> 作为默认。
布局基本结构<template><div class="layout"><header>App Header</header><slot /><footer>App Footer</footer></div></template>必须包含 <slot />,用于渲染当前页面内容;可嵌套多个具名插槽。
全局样式/逻辑可在布局中引入全局 CSS、状态管理(如 useState)或错误边界(<NuxtErrorBoundary>)。避免在布局中执行高成本数据获取(会影响所有使用该布局的页面)。
自动导入布局组件无需手动注册;Nuxt 自动将其纳入可用布局池。布局名由文件名决定(PascalCase 转 kebab-case,如 dashboard.vue → 名称 “dashboard”)。

5.2 多布局切换(definePageMeta 配置)

方法/配置语法用途注意事项
definePageMeta 宏definePageMeta({ layout: 'dashboard' })在页面组件顶部声明使用指定布局(如 dashboard.vue)。必须在 <script setup> 顶层调用;不能在条件语句或函数内使用。
布局名称匹配布局名对应 app/layouts/ 下的文件名(不带扩展名),支持 kebab-case 或 PascalCase。layout: ‘auth’ → 匹配 auth.vue;layout: ‘AuthLayout’ → 匹配 AuthLayout.vue。
禁用布局definePageMeta({ layout: false })页面不使用任何布局,直接渲染自身内容。适用于登录页、全屏图表等无通用结构的页面。
默认布局省略若页面未调用 definePageMeta 或未设置 layout,则自动使用 default.vue。推荐显式声明以提高可读性,尤其在大型项目中。
类型安全支持VS Code 会提示可用的布局名称(基于 layouts/ 目录内容)。若新增布局后未提示,重启开发服务器以刷新类型生成。

5.3 嵌套布局与插槽传递

场景实现方式说明注意事项
布局继承子布局通过 <NuxtLayout name="parent" /> 嵌套父布局<template><NuxtLayout name="default"><aside>Admin Sidebar</aside><slot /></NuxtLayout></template>(app/layouts/admin.vue)子布局仍需包含 <slot /> 以传递页面内容至父布局。
多层嵌套支持任意层级(如 marketing → default → root)每层通过 name 属性指定上一级布局。过深嵌套可能影响性能和可维护性;建议不超过 2–3 层。
插槽内容传递页面内容通过 <slot /> 逐层向上传递,最终注入到最外层布局的 <slot /> 位置。所有中间布局必须保留 <slot />,否则页面内容丢失。不支持具名插槽跨层传递;需在每层显式定义并透传。
布局间通信通过 useState、provide/inject 或 props(结合 <NuxtLayout :prop="value" />)实现。<NuxtLayout> 支持传递 props 到目标布局组件。避免过度依赖布局通信;复杂状态应提升至应用根或状态管理。
错误隔离每个布局可独立包裹 <NuxtErrorBoundary>,防止局部错误影响全局。<NuxtErrorBoundary><slot /></NuxtErrorBoundary>推荐在关键布局(如 dashboard)中添加错误边界。

5.4 动态布局与条件渲染

方法语法示例用途注意事项
运行时动态布局不支持直接在 definePageMeta 中使用变量或函数返回布局名。definePageMeta 是构建时宏,仅接受静态字面量。无法根据用户角色、路由参数等动态切换布局。
替代方案:条件渲染布局内容在 default.vue 中根据状态渲染不同结构<template><div v-if="isAuth"><AuthHeader /><slot /></div><div v-else><PublicHeader /><slot /></div></template>通过 useRoute()、useState() 获取状态;保持单一布局文件。
基于路由规则的布局在 nuxt.config.ts 中使用 routeRules 静态分配布局(构建时确定)routeRules: { '/admin/**': { definePageMeta: { layout: 'admin' } } }适用于路径前缀固定的场景(如 /admin、/user)。
使用中间件切换在页面级中间件中重定向到不同布局的代理页面(不推荐)增加路由复杂度;破坏布局语义。仅作为最后手段;优先使用静态布局分配或条件渲染。
响应式布局切换(客户端)在布局组件内部使用 ref + watch 动态改变 UI 结构仅改变视觉结构,不切换布局组件本身。适用于主题切换、响应式侧边栏等场景。

第六章:数据获取与状态管理

6.1 useAsyncData:服务端/客户端统一数据获取

方法名称语法用途代码示例注意事项
useAsyncDataconst { data, pending, error, refresh } = useAsyncData(key, handler, options?)在服务端(SSR)或客户端(CSR)执行异步数据获取,并自动序列化结果到页面。const { data } = useAsyncData('posts', () => $fetch('/api/posts'))key 必须唯一,用于缓存和刷新;handler 在服务端执行时无浏览器 API(如 window);返回值必须可 JSON 序列化
key 参数字符串或响应式引用(如 ref('user-1')标识数据请求,用于缓存和 refresh() 触发。const userId = ref('123'); useAsyncData(userId, () => fetchUser(userId.value))若使用响应式 key,变更时会自动重新请求(需配合 watch 选项)。
options.lazy布尔值,默认 false若为 true,组件挂载时不阻塞渲染(pending 初始为 false)。useAsyncData('data', fetchData, { lazy: true })适用于非关键数据(如推荐内容),提升首屏速度。
options.server布尔值,默认 true控制是否在服务端执行 handler。设为 false 则仅在客户端运行。useAsyncData('geo', () => getGeoLocation(), { server: false })用于访问浏览器专属 API(如定位、localStorage)。
refresh() 方法无参数函数手动重新执行 handler 并更新 data。const { refresh } = useAsyncData('list', fetchList); refresh()可用于”重新加载”按钮;支持 await refresh() 等待完成。

6.2 useFetch:简化 API 请求

方法名称语法用途代码示例注意事项
useFetchconst { data, error, pending } = useFetch(url, options?)基于 $fetch 的封装,自动处理 API 请求,支持 SSR/CSR 统一调用。const { data } = useFetch('/api/profile')内部调用 $fetch,继承其所有特性;自动推断 URL 类型(字符串或请求对象)
baseURL 配置在 nuxt.config.ts 中设置全局 API 基础路径,避免硬编码。runtimeConfig: { public: { apiBase: '/api' } } 配合 useFetch('/user', { baseURL: useRuntimeConfig().public.apiBase })推荐通过 runtimeConfig.public 管理公共 API 地址。
请求头/方法定制通过 options 传入支持自定义 method、headers、body 等。useFetch('/login', { method: 'POST', body: { email, password } })敏感头(如 Authorization)应在服务端注入,避免暴露在客户端。
类型安全响应泛型支持显式指定返回数据类型。interface User { id: number; name: string }; const { data } = useFetch<User>('/api/user')配合 TypeScript 可获得完整 IDE 提示和编译检查。
错误处理通过 error 响应式引用捕获请求失败信息。const { error } = useFetch('/api/data'); if (error.value) { console.error(error.value.message) }error 为 null 表示成功;非空时包含 message 和原始错误对象。

6.3 响应式依赖监听(watch 选项)

选项名称语法用途代码示例注意事项
watch(在 useAsyncData/useFetch 中)useAsyncData(key, handler, { watch: [ref1, ref2] })当指定的响应式源变更时,自动重新执行数据获取。const page = ref(1); useAsyncData('items', () => fetchItems(page.value), { watch: [page] })仅监听浅层变化;不适用于复杂对象(需用 deep: true 手动 watch)
监听路由参数结合 useRoute()当 URL 参数变化时刷新数据。const route = useRoute(); useAsyncData('post', () => fetchPost(route.params.id), { watch: [() => route.params.id] })推荐使用计算属性包装参数以提高可读性。
多依赖监听数组形式传入多个 ref/computed同时监听多个状态变化。useFetch('/search', { query: { q: searchTerm.value, category: selectedCat.value }, watch: [searchTerm, selectedCat] })避免监听无关状态,防止不必要的请求。
手动 watch 替代使用 Vue 的 watch()更精细控制(如防抖、节流)。watch(debounceSearch, (newVal) => { if (newVal) fetchData(newVal) })useAsyncData 的 watch 无防抖;高频变更场景建议手动控制。

6.4 缓存策略(cache.maxAge、swr)

缓存选项语法用途代码示例注意事项
getCachedData / 内部缓存自动基于 key 缓存同一 key 在同一次请求周期内复用数据,避免重复请求。两次调用相同 key,第二次直接返回缓存仅限当前请求上下文(SSR)或组件实例(CSR)有效。
options.cache(Nitro 缓存)useAsyncData('data', handler, { cache: { maxAge: 60 } })在 Nitro 服务端启用持久化缓存(需部署环境支持)。useAsyncData('news', () => $fetch('/external-api'), { cache: { maxAge: 300 } })仅在服务端生效;需 Nitro 缓存驱动(如 Redis、memory)配置
SWR(Stale-While-Revalidate)useAsyncData('data', handler, { getCachedData: () => cached, immediate: true })先返回旧数据(stale),后台静默更新(revalidate)。Nuxt 4 尚未内置 SWR 选项,需结合 useState + onMounted 手动实现。官方计划未来支持;当前可通过组合 useAsyncData + 定时 refresh 模拟。
客户端缓存控制使用 useState 存储结果避免组件切换时重复请求。const cached = useState('posts'); if (!cached.value) { const { data } = await useAsyncData('posts', fetchPosts); cached.value = data.value }适用于静态或低频更新数据;注意内存泄漏风险。

6.5 useState:跨组件状态共享与持久化

方法名称语法用途代码示例注意事项
useStateconst state = useState(key, init?)创建可在整个应用中共享的响应式状态(类似 Pinia 的轻量替代)。const counter = useState('counter', () => 0); counter.value++key 必须全局唯一;状态在 SSR/CSR 间自动同步(通过 payload 序列化)
跨组件共享多个组件使用相同 key所有调用 useState('user') 的组件引用同一状态对象。ComponentA.vue 和 ComponentB.vue 中使用 useState('user') 获取同一引用修改任一处,其他组件自动响应更新。
初始化函数init 仅在状态不存在时执行避免重复初始化(尤其在 SSR 中)。useState('config', () => ({ theme: 'dark' }))init 必须是纯函数;不可包含副作用或异步逻辑。
服务端持久化状态在 SSR 期间生成,并序列化到 HTML payload客户端激活(hydration)时恢复状态,避免闪烁。export default defineEventHandler(() => { useState('serverTime', () => Date.now()) })仅限可序列化数据(对象、数组、基本类型);函数、Symbol 会被忽略。
重置状态直接赋值 null 或新值清除或更新共享状态。useState('cart').value = []无内置 reset() 方法;需手动管理初始值。

第七章:路由与导航控制

7.1 navigateTo:程序化导航(支持外部链接)

方法名称语法用途代码示例注意事项
navigateTonavigateTo(to, options?)在组件、composable 或服务端逻辑中执行页面跳转。navigateTo('/dashboard')在服务端调用会触发 302 重定向;在客户端调用等效于 Vue Router 的 router.push()
内部路由跳转字符串路径或路由对象导航至应用内页面。navigateTo({ path: '/user', query: { id: '123' } })路径必须以 / 开头;支持 query、hash 等 Vue Router 选项。
外部链接跳转完整 URL(含协议)跳转到站外地址(如 OAuth 登录页)。navigateTo('https://example.com/login', { external: true })必须显式设置 external: true,否则会被视为无效内部路由。
替换当前历史记录options.replace: true使用 router.replace() 而非 push(),不留下返回记录。navigateTo('/success', { replace: true })适用于登录后跳转首页,避免用户返回登录页。
服务端重定向状态码options.redirectCode自定义 HTTP 重定向状态码(默认 302)。navigateTo('/new-path', { redirectCode: 301 })仅在服务端生效;301 有利于 SEO,302 为临时跳转。
错误处理抛出错误中断导航若导航被中间件阻止,可捕获错误。try { await navigateTo('/protected') } catch (e) { console.error('Navigation blocked') }实际开发中较少手动 try-catch;通常由中间件统一处理。

7.2 路由中间件(middleware/)

概念/类型说明文件位置与命名注意事项
全局中间件对所有路由生效middleware/global.global.ts(必须含 .global 后缀)按字母顺序执行;可用于日志、全局加载状态等。
页面级中间件仅对特定页面生效middleware/auth.ts,并在页面中通过 definePageMeta({ middleware: 'auth' }) 引用支持数组:middleware: ['auth', 'logger']
中间件函数签名export default defineNuxtRouteMiddleware((to, from) => { ... })接收 to(目标路由)、from(来源路由)上下文可返回 navigateTo()、abortNavigation() 或 undefined(继续)
阻止导航return abortNavigation() 或抛出错误if (!isAuthenticated) { return navigateTo('/login') }abortNavigation() 会取消跳转并保留当前页面;通常配合重定向使用
异步中间件支持 awaitconst user = await fetchUser(); if (!user.roles.includes('admin')) { return navigateTo('/unauthorized') }需确保异步操作快速完成,避免阻塞首屏渲染
中间件执行时机SSR 时在服务端执行,CSR 时在客户端执行同一份中间件代码在两端运行避免使用浏览器专属 API(如 localStorage);敏感逻辑应在服务端验证

7.3 页面元信息(definePageMeta)

元信息字段类型用途代码示例注意事项
layoutstring | false指定页面使用的布局definePageMeta({ layout: 'dashboard' })布局名对应 app/layouts/ 下的文件名(不含扩展名)
middlewarestring | string[]关联一个或多个中间件definePageMeta({ middleware: ['auth', 'permission'] })中间件按数组顺序执行;需提前在 middleware/ 中定义
namestring为路由指定唯一名称(用于 router.push({ name: '...' })definePageMeta({ name: 'UserProfile' })默认路由名由路径生成(如 /user/[id] → user-id)
aliasstring | string[]设置路由别名definePageMeta({ alias: ['/profile'] })访问 /profile 会渲染当前页面内容
redirectstring访问此页面时自动重定向definePageMeta({ redirect: '/new-page' })构建时静态重定向;适用于废弃页面迁移
title / meta不直接支持页面标题和 meta 标签应通过 <head> 或 useHead() 控制useHead({ title: 'My Page' })definePageMeta 不处理 SEO 相关元数据

7.4 路由守卫与权限控制

场景实现方式说明注意事项
用户认证守卫在 auth 中间件中检查登录状态const token = useCookie('auth_token'); if (!token.value && to.path !== '/login') { return navigateTo('/login') }Cookie 在 SSR/CSR 均可读取;比 localStorage 更安全(可设 HttpOnly)
角色权限控制结合用户角色与页面所需权限const requiredRole = to.meta.requiredRole; if (user.role !== requiredRole) { return navigateTo('/forbidden') }权限信息应从服务端获取(如 /api/me),避免客户端伪造
动态权限路由在中间件中调用 API 获取用户权限const { data: permissions } = await useAsyncData('perms', () => $fetch('/api/permissions')); if (!permissions.value.includes(to.name)) { return abortNavigation() }增加请求延迟;建议缓存权限数据(如 useState('userPermissions')
游客/会员分流根据认证状态重定向不同首页if (to.path === '/') { if (isLoggedIn) navigateTo('/dashboard'); else navigateTo('/welcome') }避免无限重定向循环;确保目标页面不触发相同逻辑
全局错误拦截在中间件末尾添加兜底处理if (error) { return navigateTo('/error') }需配合 onErrorCaptured 或 Nitro 错误处理机制

第三部分:全栈能力与服务端开发

第八章:Nitro 服务端引擎入门

8.1 server/ 目录结构与执行上下文

概念/目录说明注意事项
server/ 根目录所有服务端逻辑的入口目录,由 Nitro 引擎在构建时自动扫描并打包为独立服务。此目录代码仅在服务端运行,不可引用 Vue 组件、浏览器 API(如 window、localStorage)。
执行上下文(Context)每个 API 路由或中间件函数接收一个 event 对象(类型为 H3Event),包含请求/响应信息。通过 event.context 可传递自定义数据(如用户身份)到下游中间件或 API。
环境隔离开发环境使用本地 Node.js 服务器;生产环境可部署至 Serverless(Vercel、Netlify)、Docker 或传统 Node 服务器。构建产物位于 .output/,包含独立可运行的服务端包。
自动热重载修改 server/ 下文件后,开发服务器自动重启服务端逻辑(比前端 HMR 慢)。避免在服务端引入大型依赖,以免延长重启时间。
类型支持Nitro 基于 H3(HTTP 框架),提供完整的 TypeScript 类型推导(如 getRequestURL, getCookie)。推荐使用 defineEventHandler、defineRoute 等宏以获得最佳类型体验。

8.2 API 路由(server/api/)

路由命名规则:

文件命名规则对应 HTTP 方法路由路径示例说明注意事项
hello.tsGET/api/hello默认处理 GET 请求若需支持多方法,需显式判断 event.method
user.post.tsPOST/api/user仅处理 POST 请求文件名中的 .post 指定 HTTP 方法
item/[id].tsGET/api/item/123支持动态参数(通过 event.context.params.id 获取)参数名必须与方括号内一致
upload.post.tsPOST/api/upload可处理表单、JSON、文件上传使用 readFormData()、readBody() 解析请求体
*.ts(通配符)任意匹配任意子路径如 proxy/[…].ts → /api/proxy/any/path适用于反向代理、CMS 路由等场景

API 处理函数工具:

方法/工具语法用途代码示例注意事项
defineEventHandlerexport default defineEventHandler((event) => { ... })定义 API 处理函数,自动注入 event 上下文export default defineEventHandler((event) => { return { message: 'Hello from API' } })返回值自动序列化为 JSON;支持 Promise
getRouterParamsgetRouterParams(event)获取动态路由参数const { id } = getRouterParams(event)替代 event.context.params,类型更安全
readBodyawait readBody(event)读取 JSON 或表单请求体const body = await readBody(event)仅可读取一次;大文件建议用流式处理
setResponseStatussetResponseStatus(event, 404)设置 HTTP 状态码if (!user) { setResponseStatus(event, 404); return { error: 'Not found' } }默认状态码为 200;错误场景需显式设置
useRuntimeConfiguseRuntimeConfig(event)在服务端读取私有配置(如数据库密码)const config = useRuntimeConfig(event); const dbUrl = config.dbUrl私有配置不会暴露给客户端;仅 public 字段会同步到前端

8.3 服务器中间件(server/middleware/)

文件命名执行顺序用途代码示例注意事项
logger.ts按字母顺序(a → z)全局日志记录、性能监控export default defineEventHandler((event) => { console.log('Request:', event.path) })中间件无返回值时继续执行下一个;返回值将终止链并作为响应
auth.ts在 logger.ts 之后(若命名靠后)身份验证、权限检查export default defineEventHandler((event) => { const token = getHeader(event, 'authorization'); if (!verifyToken(token)) { setResponseStatus(event, 401); return { error: 'Unauthorized' } } })返回响应对象会中断后续中间件和 API 执行
cors.ts通常命名靠前(如 00.cors.ts)设置 CORS 头export default defineEventHandler((event) => { setHeaders(event, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST' }) })可通过前缀数字控制执行优先级
中间件链机制串行执行类似 Express/Koa 的中间件栈所有中间件共享 event.context可在中间件中设置 event.context.user = user 供 API 使用
错误处理中间件无特殊命名;靠逻辑判断捕获上游抛出的错误export default defineEventHandler((event) => { try { ... } catch (e) { return { error: e.message } } })Nitro 不支持 next(err);需手动 try-catch 或使用 onError 钩子

8.4 服务器工具函数(server/utils/)

工具类型存放位置用途代码示例注意事项
通用函数server/utils/hash.ts封装加密、格式化等逻辑export function sha256(str: string) { ... }可被 API、中间件、其他工具函数 import 使用
数据库连接server/utils/db.ts初始化并导出数据库客户端import { createClient } from 'redis'; const client = createClient(); await client.connect(); export default client避免在每次请求中新建连接;应复用全局实例
第三方 SDK 封装server/utils/qrcode.ts封装外部服务(如生成二维码)import QRCode from 'qrcode'; export async function generateQR(text: string) { return await QRCode.toDataURL(text) }第三方库需支持 Node.js 环境(无 DOM 依赖)
类型安全调用在 API 中 import 使用保持服务端逻辑模块化import { generateQR } from '~/server/utils/qrcode'; export default defineEventHandler(async (event) => { const url = getQuery(event).url as string; return await generateQR(url) })路径别名 ~ 在服务端同样有效
热重载限制修改工具函数后需重启服务端(因被缓存)无直接解决方案开发时可将高频调试逻辑临时移至 API 文件内

第九章:前后端一体化开发实践

9.1 前端调用后端 API($fetch 与类型安全)

方法/机制语法用途代码示例注意事项
$fetch(Nuxt 封装)const data = await $fetch('/api/user')在组件、composable 或服务端中统一调用 API,自动处理 baseURL、序列化等。const { data } = await useAsyncData('user', () => $fetch('/api/profile'))内部基于 ofetch;自动继承 runtimeConfig.app.baseURL
类型安全响应泛型指定返回结构避免运行时类型错误,提升 IDE 体验。interface UserProfile { id: number; name: string }; const user = await $fetch<UserProfile>('/api/profile')推荐在 types/ 目录定义共享接口,前后端共用。
错误处理捕获 FetchError处理网络错误、4xx/5xx 响应。try { await $fetch('/api/data') } catch (error) { if (error.statusCode === 401) navigateTo('/login') }$fetch 抛出的错误包含 statusCode、statusMessage 等字段。
请求头自动注入通过插件或拦截器如自动携带认证 Token。export default defineNuxtPlugin((nuxtApp) => { nuxtApp.$fetch.onRequest(({ options }) => { const token = useCookie('auth_token').value; if (token) options.headers = { ...options.headers, Authorization: 'Bearer ' + token } }) })插件需注册为 plugins/fetch.client.ts(仅客户端)或通用插件。
服务端调用优势在 useAsyncData 中调用自动走本地 Nitro 服务,避免跨域和公网请求。useAsyncData('list', () => $fetch('/api/items'))生产部署后,Nitro 会内联 API 调用(zero-overhead)。

9.2 文件上传与解析(如二维码工具案例)

场景实现方式说明代码示例注意事项
前端文件选择<input type="file"> + ref获取用户选择的文件对象。<template><input type="file" @change="handleFile" /></template><script setup>const handleFile = (e) => { const file = e.target.files[0]; ... }</script>支持多文件、accept 限制(如 accept=“image/*“)
客户端上传 API使用 FormData + $fetch将文件作为 multipart/form-data 发送。const formData = new FormData(); formData.append('image', file); await $fetch('/api/upload', { method: 'POST', body: formData })浏览器自动设置 Content-Type: multipart/form-data; boundary=…
服务端接收文件readFormData() 解析在 server/api/upload.post.ts 中读取上传内容。export default defineEventHandler(async (event) => { const formData = await readFormData(event); const file = formData.get('image') as File; ... })File 对象包含 name、size、type 和 arrayBuffer() 方法
二维码生成案例服务端调用 qrcode 库上传图片后返回二维码 URL。import QRCode from 'qrcode'; export async function generateQR(text: string) { return await QRCode.toDataURL(text) }; export default defineEventHandler(async (event) => { const { url } = await readBody(event); return { qr: await generateQR(url) } })第三方库需支持 Node.js;避免在客户端使用(体积大)
文件安全校验服务端验证类型/大小防止恶意文件上传。if (file.type !== 'image/png') throw createError({ statusCode: 400, message: 'Only PNG allowed' }); if (file.size > 5 * 1024 * 1024) throw createError({ statusCode: 400, message: 'File too large' })客户端校验可被绕过;服务端必须二次验证

9.3 环境变量与私有配置(runtimeConfig)

配置类型存放位置可见性代码示例注意事项
公共配置(客户端可见)nuxt.config.ts → runtimeConfig.public前端可通过 useRuntimeConfig().public.xxx 访问// nuxt.config.ts; runtimeConfig: { public: { apiBase: process.env.NUXT_PUBLIC_API_BASE } }}
私有配置(仅服务端)nuxt.config.ts → runtimeConfig 根级仅在 server/ 中通过 useRuntimeConfig(event) 访问// .env; DB_PASSWORD=secret123; // nuxt.config.ts; runtimeConfig: { dbPassword: process.env.DB_PASSWORD }敏感信息(密码、密钥)必须放在此处;不会暴露给前端
环境变量加载.env、.env.local 等启动时自动注入 process.env# .env.local; NUXT_PUBLIC_API_BASE=https://prod.api.com; DB_PASSWORD=prod_secret.env.local 通常加入 .gitignore;不同环境使用不同文件
配置优先级运行时 > 构建时NUXT_ 前缀变量可覆盖配置NUXT_DB_PASSWORD=override npm run dev适用于 CI/CD 动态注入密钥
类型安全访问自动生成类型VS Code 提示可用配置项const config = useRuntimeConfig(); console.log(config.public.apiBase)若类型未更新,重启 dev server 刷新 .nuxt/types/

9.4 错误处理与日志记录

机制用途实现方式代码示例注意事项
服务端错误抛出统一错误格式使用 createError()if (!user) { throw createError({ statusCode: 404, message: 'User not found' }) }自动设置状态码、序列化错误信息;客户端可通过 error.data 获取
客户端错误捕获在 useAsyncData/useFetch 中通过 error 响应式引用const { error } = useFetch('/api/data'); if (error.value) { showError(error.value) }showError() 会触发全局错误页面(error.vue)
全局错误页面app/error.vue自定义错误展示 UI<template><div>Error {{ error?.statusCode }}: {{ error?.message }}</div></template><script setup>defineProps(['error'])</script>接收 error prop(类型 NuxtError);支持重试按钮
服务端日志记录在中间件或 API 中console.log 或集成日志库export default defineEventHandler((event) => { console.log('[' + new Date().toISOString() + '] ' + event.method + ' ' + event.path) })生产环境建议使用 pino、winston 等结构化日志库
客户端日志上报错误边界 + 上报 API捕获未处理异常onErrorCaptured((err) => { $fetch('/api/log-error', { method: 'POST', body: { message: err.message } }); return false })避免无限上报;添加采样率控制

第四部分:工程化与部署

第十章:TypeScript 与类型安全

10.1 Nuxt 4 的 TypeScript 项目结构

文件/目录作用说明注意事项
nuxt.config.ts项目主配置文件使用 defineNuxtConfig() 提供类型安全的配置选项。必须以 .ts 扩展名创建;Nuxt 自动识别并启用 TS 支持。
tsconfig.json根级 TypeScript 配置由 Nuxt 自动生成(若不存在),包含基础编译选项。开发者通常无需修改;高级需求可扩展(见 10.3 节)。
types/(推荐)共享类型定义目录存放接口、枚举等(如 User.ts、ApiResponse.ts)。可被前端组件和服务端 API 共同引用,实现前后端类型对齐。
app/**/*.vueVue 单文件组件支持 <script setup lang="ts"> 编写组合式 API。组件 props 应使用 defineProps<{ ... }>() 启用严格类型检查。
server/**/*.ts服务端逻辑包括 API、中间件、工具函数,运行于 Node.js 环境。可使用 Node.js 内置模块(如 fs、path),但不可引用浏览器 API。
.nuxt/自动生成目录包含类型声明(types/)、构建产物、路由映射等。不应提交到 Git;类型文件在此目录下实时更新。
composables/组合函数自动导入的 TS 函数(如 useAuth.ts),返回响应式状态或方法。必须导出默认函数;命名以 use 开头以符合约定。

10.2 自动类型生成(组件、API、composables)

生成目标触发时机生成位置说明注意事项
全局组件类型开发服务器启动或组件变更.nuxt/types/components.d.ts为 app/components/ 下所有组件生成全局类型声明。组件必须使用 defineProps 定义 props,否则类型为 any。
Composables 类型文件保存时.nuxt/types/composables.d.ts为 composables/ 下函数生成自动导入类型(如 useCounter(): { count: Ref<number> })。函数必须 export default;参数和返回值需显式标注类型。
API 路由类型构建或开发启动.nuxt/types/nitro.d.ts为 server/api/ 生成请求/响应类型的 TypeScript 接口(实验性,需配合插件)。目前 Nuxt 4 不自动推断 API 类型;推荐手动定义共享接口。
页面元信息类型使用 definePageMeta 时内联类型推导VS Code 自动提示可用布局、中间件名称。布局/中间件文件变更后需重启 dev server 刷新类型。
运行时配置类型nuxt.config.ts 修改.nuxt/types/runtime-config.d.ts为 runtimeConfig 和 publicRuntimeConfig 生成类型。确保在 nuxt.config.ts 中显式声明所有配置字段。
替代方案:手动共享 API 类型开发者维护types/api.ts// types/api.ts; export interface UserProfile { id: number; name: string }; // server/api/profile.get.ts; import { UserProfile } from '~/types/api'; export default defineEventHandler((): UserProfile => ({ id: 1, name: 'John' })); // pages/profile.vue; import { UserProfile } from '~/types/api'; const { data } = useFetch<UserProfile>('/api/profile')当前最可靠的方式;确保前后端使用同一接口定义。

10.3 多上下文 tsconfig 配置(应用 vs 服务端)

上下文配置文件用途关键配置项注意事项
应用(客户端 + SSR 渲染)tsconfig.app.json(自动生成)编译 Vue 组件、composables、页面等"module": "ESNext", "target": "ES2020", "lib": ["ESNext", "DOM"], "include": ["app", "composables", "types"]包含 DOM 库(因 CSR 需要);不包含 Node.js 模块
服务端(Nitro 引擎)tsconfig.server.json(自动生成)编译 server/ 目录下的代码"module": "NodeNext", "target": "ES2022", "lib": ["ES2022"], "types": ["node"], "include": ["server", "types"]包含 @types/node;无 DOM 库(避免误用浏览器 API)
根配置(共享基础)tsconfig.json定义公共编译选项"strict": true, "esModuleInterop": true, "skipLibCheck": true, "paths": { "~/*": ["./*"] }启用 strict 模式提升类型安全;paths 支持 ~ 别名
自定义扩展手动创建/修改覆盖默认配置"jsx": "preserve", "baseUrl": ".", "types": ["vite/client"]修改后需重启 dev server;避免破坏 Nuxt 自动生成的子配置
类型隔离验证开发时分别校验两端代码客户端代码误用 fs 会报错;服务端代码使用 window 会报错多上下文配置有效防止跨环境 API 误用,提升代码健壮性

第十一章:构建、部署与性能优化

11.1 构建命令与输出分析

操作/文件说明命令或路径注意事项
构建命令生成生产环境可部署产物npm run build(等价于 nuxi build)首次构建较慢(需编译依赖);后续增量构建更快
构建输出目录包含前端资源和服务端包.output/.output/public/:静态资源(CSS、JS、图片);.output/server/:Nitro 服务端 bundle(Node.js 可执行)
客户端资源由 Vite 生成的优化资产.output/public/_nuxt/文件名含哈希(如 entry.abc123.js),支持长期缓存
服务端入口Nitro 生成的统一入口.output/server/index.mjs可直接通过 node .output/server/index.mjs 启动服务
预渲染页面(SSG)若启用 SSG,生成 HTML 文件.output/public/ 下对应路径(如 about/index.html)仅对 prerender 路由生效(见 11.3 节)
构建分析工具可视化 bundle 体积安装 @nuxt/analyze 模块:modules: ['@nuxt/analyze']用于识别过大依赖(如 lodash 全量引入);构建后自动打开分析报告

11.2 部署目标(Vercel、Netlify、Node.js 服务器)

部署平台配置方式优势注意事项
Vercel无需配置;推送 Git 仓库自动部署原生支持 Nuxt 4;自动识别 SSR/SSG;免费 Serverless 函数确保项目根目录有 package.json;Vercel 会自动运行 build
Netlify创建 netlify.toml 或使用 UI 配置支持 Edge Functions(实验性 Nitro 集成)默认部署为静态站点;若需 SSR,需启用 Netlify Functions 并配置 functions 目录
Node.js 服务器手动部署 .output/ 目录完全控制运行环境(如 PM2、Docker)启动命令:node .output/server/index.mjs;需开放端口(默认 3000)
Docker编写 Dockerfile便于容器化部署(K8s、云厂商)示例:FROM node:20-alpine; COPY .output ./app; WORKDIR /app; EXPOSE 3000; CMD ["node", "server/index.mjs"]
静态托管(纯 SSG)仅部署 .output/public/适用于无服务端逻辑的博客、文档站通过 nuxi generate 生成完整静态站点(所有路由预渲染)

11.3 静态站点生成(SSG)与混合渲染

渲染模式配置方式适用场景代码示例注意事项
纯 SSG在 nuxt.config.ts 中设置内容不变或低频更新的站点(如文档、营销页)export default defineNuxtConfig({ ssr: true, nitro: { prerender: { routes: ['/', '/about', '/posts/1'] } } })未列入 prerender.routes 的动态路由仍为 SSR
混合渲染(Hybrid)使用 routeRules 按路由指定同一项目中部分页面 SSG、部分 SSR/CSRrouteRules: { '/blog/**': { ssr: true }, '/docs/**': { prerender: true }, '/dashboard/**': { ssr: false } }构建时自动分类处理;部署后各路由独立响应
客户端渲染(CSR)ssr: false 或 routeRules 设置高交互性应用(如管理后台),SEO 不敏感definePageMeta({ ssr: false })首屏加载较慢;需确保关键内容不依赖 CSR
增量静态再生(ISR)Nitro 实验性支持SSG 页面在访问时后台更新(类似 Next.js ISR)routeRules: { '/news/**': { isr: true } }需部署平台支持缓存刷新(如 Vercel);Nuxt 4 尚未完全稳定
预渲染动态路由在 nitro.prerender.crawlLinks 或手动指定从首页链接自动发现并预渲染nitro: { prerender: { crawlLinks: true, routes: ['/'] } }适用于博客文章列表页自动抓取子页面

11.4 SEO 优化(meta 标签、多语言结构)

优化项实现方式说明代码示例注意事项
动态 meta 标签使用 useHead()在组件中设置 title、description、og:image 等const { data } = useAsyncData('post', fetchPost); useHead({ title: data.value?.title, meta: [{ name: 'description', content: data.value?.excerpt }] })useHead 支持响应式数据;SSR 时正确注入到 HTML <head>
结构化数据(JSON-LD)在 useHead 中添加 script提升搜索引擎对内容的理解useHead({ script: [{ type: 'application/ld+json', children: JSON.stringify({ "@context": "https://schema.org", "@type": "Article", "headline": data.value.title }) }] })避免内联大段 JSON;确保符合 schema.org 规范
多语言 SEO设置 hreflang 和 canonical告知搜索引擎多语言版本关系useHead({ link: [{ rel: 'canonical', href: 'https://site.com' + route.path }, { rel: 'alternate', hreflang: 'en', href: 'https://site.com/en/about' }, { rel: 'alternate', hreflang: 'zh', href: 'https://site.com/zh/about' }] })hreflang 必须成对出现;包含 x-default 默认版本更佳
Open Graph / Twitter Cards在 meta 中定义优化社交分享卡片显示useHead({ meta: [{ property: 'og:title', content: title }, { property: 'og:image', content: imageUrl }, { name: 'twitter:card', content: 'summary_large_image' }] })图片建议尺寸 ≥ 1200×630px;使用绝对 URL
robots.txt 与 sitemap放入 public/ 目录控制爬虫行为和索引范围# public/robots.txt; User-agent: *; Allow: /; Sitemap: https://site.com/sitemap.xml动态站点可使用 @nuxtjs/sitemap 模块自动生成 sitemap

第十二章:模块与插件系统

12.1 官方模块集成(如 @nuxtjs/tailwindcss)

模块名称安装命令配置方式功能说明注意事项
@nuxtjs/tailwindcssnpm install -D @nuxtjs/tailwindcssmodules: ['@nuxtjs/tailwindcss']自动配置 Tailwind CSS,支持 JIT 模式、PurgeCSS、主题定制。无需手动创建 tailwind.config.js;默认启用 content 扫描 app/ 目录。
@nuxtjs/eslint-modulenpm install -D @nuxtjs/eslint-modulemodules: ['@nuxtjs/eslint-module']在开发服务器中集成 ESLint 实时检查。需提前安装 eslint 及配置文件(如 .eslintrc)。
@nuxt/imagenpm install @nuxt/imagemodules: ['@nuxt/image']提供 <NuxtImg> 组件,支持自动优化、懒加载、CDN 集成。默认使用内置 IPX 引擎;生产环境建议配置外部 provider(如 Cloudinary)。
@nuxt/devtools创建项目时可选,或手动安装modules: ['@nuxt/devtools']启用可视化 DevTools(组件树、路由、状态监控)。仅在开发环境加载;生产构建自动剥离。
@nuxtjs/color-modenpm install @nuxtjs/color-modemodules: ['@nuxtjs/color-mode']支持深色/浅色主题切换,自动持久化用户偏好。提供 $colorMode.preference 响应式状态和 class 注入(如 dark)。
模块配置扩展在 nuxt.config.ts 中传入选项modules: [['@nuxtjs/tailwindcss', { exposeConfig: true }]]大多数模块支持传入配置对象以覆盖默认行为。查阅模块文档获取可用选项;类型提示由模块提供。

12.2 自定义插件开发(生命周期钩子)

插件类型文件位置注册方式用途代码示例注意事项
通用插件plugins/myPlugin.ts自动注册(无需手动引入)扩展 Vue 应用、注入全局属性、监听生命周期。export default defineNuxtPlugin((nuxtApp) => { nuxtApp.provide('hello', (name: string) => 'Hello ' + name + '!') })插件名必须以 .client、.server 或无后缀结尾;无后缀表示两端运行。
客户端插件plugins/ga.client.ts仅在客户端执行集成浏览器专属库(如 Google Analytics、埋点 SDK)。export default defineNuxtPlugin(() => { if (process.client) { initGA() } })文件名必须含 .client 后缀,否则会在 SSR 中报错。
服务端插件plugins/db.server.ts仅在服务端执行初始化数据库连接、缓存客户端等。export default defineNuxtPlugin(async () => { const db = await createConnection(); return { provide: { db } } })文件名必须含 .server 后缀;返回值可通过 useNuxtApp().$db 访问。
注入全局方法在插件中使用 provide组件中通过 $xxx 调用类似 Vue 2 的 Vue.prototypenuxtApp.provide('formatDate', (d) => new Date(d).toLocaleDateString()); const formatted = useNuxtApp().$formatDate(date)推荐优先使用 composables/;插件适用于跨上下文共享逻辑。
生命周期钩子在插件或 nuxt.config.ts 中监听构建、渲染等阶段事件如 builder:prepared、vue:setuphooks: { 'pages:extend'(pages) { pages.push({ name: 'custom', path: '/custom', file: '~/pages/custom.vue' }) } }钩子在 plugins/ 中通过 nuxtApp.hooks.hook() 使用;配置文件中通过 hooks 对象注册。

12.3 第三方库集成最佳实践

场景推荐方式说明代码示例注意事项
纯客户端库(如地图、图表)使用 <ClientOnly> + 动态导入避免 SSR 报错(因依赖 window)<template><ClientOnly><MyChart v-if="loaded" /><template #fallback>Loading...</template></ClientOnly></template><script setup>const loaded = ref(false); onMounted(async () => { await import('chart.js'); loaded.value = true })</script>不要直接在顶层 import;防止服务端执行。
需初始化的库(如 i18n)通过插件注入统一管理实例生命周期export default defineNuxtPlugin(({ vueApp }) => { const i18n = createI18n({ ... }); vueApp.use(i18n) })确保库支持 Vue 3;避免重复安装。
大型库按需引入使用插件 + tree-shaking减少客户端包体积import { debounce } from 'lodash-es'; export default defineNuxtPlugin((nuxtApp) => { nuxtApp.provide('debounce', debounce) })优先选择 ES 模块版本(如 lodash-es);避免全量引入。
CSS 库(如 Bootstrap)在 nuxt.config.ts 中全局引入确保样式在所有页面生效css: ['bootstrap/dist/css/bootstrap.min.css']若仅局部使用,应在组件 <style> 中 @import。
TypeScript 类型支持安装 @types/xxx获得 IDE 提示和编译检查npm install -D @types/lodash检查库是否自带类型(查看 package.json 的 types 字段)。
避免污染全局作用域封装为 composable 或插件保持代码可测试性和模块化export const useMap = () => { const map = shallowRef(null); onMounted(() => { map.value = new MapLib() }); return { map } }优于直接挂载到 window 或 Vue 原型。