---
title: "Nuxt 4.6"
description: "Nuxt 4.6 通过 nuxt/server 实现服务器无关，重构了类型化 $fetch，新增会话、Vue Vapor 支持和开发错误页面，并与 Nuxt CLI v4 一同发布。"
canonical_url: "https://nuxt.zhcndoc.com/blog/v4-6"
---
# Nuxt 4.6

> Nuxt 4.6 通过 nuxt/server 实现服务器无关，重构了类型化 $fetch，新增会话、Vue Vapor 支持和开发错误页面，并与 Nuxt CLI v4 一同发布。

Nuxt 4.6 来了，还带来了 Nuxt CLI v4。这是我们规模最大的次版本发布之一，自 v4.5.2 以来包含超过 420 次提交，标志着我们朝服务器无关的 Nuxt 迈出了重要的第一步。

## 📣 一些消息

### Nuxt CLI v4

除了 Nuxt 4.6，今天还带来了 Nuxt CLI 的一个新主版本：`@nuxt/cli` v4。它作为 `nuxt` 的依赖发布，因此升级时会自动获得。大多数新功能都在 `nuxt dev` 中。

![Nuxt CLI v4 中的 nuxt dev](https://nuxt.zhcndoc.com/assets/blog/v4-6/nuxt-dev.svg)

现在终端底部会固定显示一个交互面板，包含 URL、启动进度和单键快捷方式（`r` 重启、`o` 打开、`l` 查看日志、`n` 查看请求、`p` 查看页面和服务端路由）。每个请求都有一个 id，因此日志和错误都能关联到引发它们的请求。如果您更喜欢传统输出，可以传入 `--no-tui`。

开发服务器还会告诉您重新加载或重启的原因、哪些 `nuxt.config` 键发生了变化、启动缓慢时的耗时分布，以及每个模块的初始化耗时。未产生变化的保存不再重启服务器，完全重启也会继续使用同一端口提供服务。错误通过 CLI 层的统一通道处理，并使用 `my-bad` 渲染（[详见下文](#better-errors-in-development)）。

`.nuxt/` 中的锁文件允许第二个 `nuxt dev`（例如由 agent 启动的实例）接管您启动的实例，或让其继续运行。同一个锁文件也支持新的 `nuxt curl` 和 `nuxt task` 命令，使其能够与正在运行的服务器通信，`nuxt docs "<query>"` 则会搜索已安装 Nuxt 版本的文档。您还可以使用 `nuxt preview --takeover` 替换正在运行的预览服务器。

它的体积也小了许多，启动速度更快：

|                          | v3.37   | v4.0   |             |
| ------------------------ | ------- | ------ | ----------- |
| `@nuxt/cli` 安装体积         | 13.1 MB | 3.5 MB | **-73%**    |
| `@nuxt/cli` 依赖数量         | 70      | 31     | **-56%**    |
| `nuxt dev`：首次绘制          | 330 ms  | 50 ms  | **快 6.6 倍** |
| `nuxt dev`：端口绑定          | 338 ms  | 104 ms | **快 3.2 倍** |
| `nuxt dev`：空闲内存占用（Linux） | 630 MB  | 440 MB | **-30%**    |

虽然这是一个主版本，但这些变化对 Nuxt v4 用户应该都不会造成破坏性影响：CLI 需要 Node.js v22.21+、v24.11+ 或 v26+，`nuxt init` 已被移除，请改用 `npm create nuxt@latest`，并且不再支持 Nuxt 2 和 `@nuxt/bridge`。

::read-more{icon="i-simple-icons-github" target="_blank" to="https://github.com/nuxt/cli/releases/tag/v4.0.0"}
阅读完整的 Nuxt CLI v4 发布说明。
::

### 服务器无关的 Nuxt

本次发布最重要的变化，是我们正在让 Nuxt 不再绑定特定服务器实现。

自由选择是 Web 的基本价值，也是整个 Nuxt 团队的共同理念。您可以使用 `pages/`（配合 vue-router），也可以不用。您可以使用 Vite、webpack 或 Rspack 打包代码。您可以从数十个服务商中选择部署平台，选择任意图像或字体服务商，以及任意数据库适配器。无论如何选择，框架始终相同。

服务端此前却有所不同。`#app` 组合式函数导入 h3 类型，服务端代码从 `h3` 和 `nitropack` 导入，而每个涉及服务端的模块都与 Nuxt 当时依赖的这些包的主版本绑定。在我们升级 h3 和 Nitro 的主版本时，这一点尤为明显，因为其中的破坏性变化会对整个生态系统产生连锁影响。

本次发布改变了这一点。除了明确定义 `@nuxt/kit` 中的公共 API（现在不再引用外部包），Nuxt 还为请求事件、路由规则和类型化 `$fetch` 定义了自己的类型，并通过 [`nuxt/server`](#nuxtserver) 暴露大多数应用所需的服务端工具。这项工作始于近一年前，目标是让 Nuxt 能够使用任意服务端构建器，而不仅是 Nitro，如今终于取得了成果（[#33462](https://github.com/nuxt/nuxt/pull/33462)）。

在底层，`nuxt/server` 默认仍由 Nitro 驱动。我们还宣布了第二种实验性实现 [`@nuxt/vite-server`](#experimental-nuxtvite-server)，它使用 [Vite Environment API](https://vite.dev/guide/api-environment#environment-api) 实现纯 Vite 服务端构建。

::important
我们相信，Nitro 对几乎所有人来说仍然是正确的选择。
::

我们认为 `nuxt/server` 有几个关键优势：

1. **让升级到 Nuxt 5 更平滑**，Nuxt 5 将迁移至 Nitro v3 和 h3 v2。在 4.6 中基于 `nuxt/server` 编写的服务端代码无需修改即可在那里运行，因此模块可以用同一个文件支持两个版本。
2. **将 Nuxt 与 Nitro 的发布周期解耦。** 由于 API 由我们维护，我们可以适应 Nitro 或 h3 的破坏性变化而无需发布新的主版本，也可以无需等待上游发布就推出 Nuxt 主版本。
3. **让 Nuxt 的代码更易于维护。** 它保持了我们的 API（`nuxt/app` 和 `nuxt/server`）与您最终用于构建应用的打包器和服务器之间的关注点分离。

此外还有其他优势，从统一的类型接口到更快速的功能迭代。

最后，特别感谢 [@pi0](https://github.com/pi0)，他在过去几年中始终专注于服务器无关性，并持续投入 h3、Nitro 和符合 Web 标准的服务端原语，正是这些工作让可移植的 `RequestEvent` 成为可能。谢谢你，Pooya。❤️

本次发布的几乎所有功能都已进入 Nuxt 5 分支，您现在也可以通过 `future.compatibilityVersion: 5` 尝试其余大部分 Nuxt 5 默认行为（[详见下文](#nuxt-5-features-today)）。

### Nuxt 3 生命周期结束

Nuxt 3 已于 2026 年 7 月 31 日结束生命周期，因此本次不会同时发布 3.x 版本。如果您仍在使用 v3，[升级指南](https://nuxt.zhcndoc.com/docs/getting-started/upgrade)正等着您。

如果您已经读到这里，恐怕我得告诉您一个坏消息：还有很多内容要讲。您也许该先去泡杯咖啡。☕️

## 🧩 `nuxt/server`

大家期待已久的功能，现在终于有了（[#36275](https://github.com/nuxt/nuxt/pull/36275)）！🎉

`nuxt/server` 是服务端代码的新导入来源：处理程序、中间件和工具函数。它与 `nuxt/app` 相互补充，后者用于应用中也会在浏览器运行的部分。

```ts [server/api/hello.ts]
import { defineEventHandler, getQuery } from 'nuxt/server'

export default defineEventHandler((event) => {
  const { name } = getQuery<{ name?: string }>(event)
  return { message: `Hello, ${name ?? 'world'}!` }
})
```

这些工具采用 Web 标准，并基于可移植的 `RequestEvent` 定义类型：

```ts
event.req         // Request
event.url         // URL
event.res         // { status, statusText, headers }
event.res.headers // Headers
event.context     // per-request context
```

在 `@nuxt/nitro-server` 下，这些功能由 Nitro 和 h3 实现，但您的代码无需从它们导入。因此，同一个处理程序可以在 Nitro v2、Nitro v3 或 `@nuxt/vite-server` 下运行，从 `nuxt/server` 导入的模块也不需要将 `h3` 或 `nitropack` 作为 peer dependency。我们认为，这将大大降低升级至 Nuxt v5 和 Nitro v3 的难度。

类型也变得更简单。我们不再将 h3 或 Nitro 类型提升到您的应用中，为 `useRequestEvent`、`$fetch` 或路由规则提供类型，从而消除了版本不同时的一类冲突。

这个接口范围很小，覆盖了已发布模块和用户代码通常需要的功能：`defineEventHandler`、`createError`/`isNuxtError`、请求 URL、请求头、查询参数、请求体（普通请求体，或使用任意 [Standard Schema](https://standardschema.dev) 库或函数验证）、cookie、重定向、响应状态、`getRouterParam(s)`、`getRequestIP`、`handleCors`、`getRouteRules`、`useRuntimeConfig`、`useAppConfig` 和会话。

```ts [server/api/users.post.ts]
import { defineEventHandler, readValidatedBody } from 'nuxt/server'
import { z } from 'zod'

export default defineEventHandler(async (event) => {
  const user = await readValidatedBody(event, z.object({ name: z.string() }))
  return { created: user.name }
})
```

我们鼓励您使用 Web API（例如 `event.req.headers`），如果 `nuxt/server` 中缺少您需要的功能，也欢迎提出 issue。🙏

如果某个处理程序确实需要使用 `nuxt/server` 之外的功能，也不用担心。现有功能都还在：像以前一样从 `h3` 或 `nitropack/runtime` 导入 `defineEventHandler` 和所需工具，处理程序就会保持与 Nuxt 4.5 完全相同的行为。

```ts [server/api/upload.post.ts]
import { defineEventHandler, readMultipartFormData } from 'h3'

export default defineEventHandler(async (event) => {
  const parts = await readMultipartFormData(event)
  return { received: parts?.length ?? 0 }
})
```

::important
在 Nuxt 4 中，*自动导入*的 `defineEventHandler`、`getQuery` 和 `readBody`（以及同系列的其他函数）仍然是 h3 自己的工具，它们接收的事件结构有所不同。要使用新的服务端运行时，请显式从 `nuxt/server` 导入，包括 `defineEventHandler`。如果混用两者，您会看到 `NUXT_E8012` 错误，它应该会告诉您需要更改哪个导入。
::

部分工具的行为也与 h3 v1 中的同名函数不同：`sendRedirect` 返回响应而非发送响应，`createError` 接收 `status` 和 `statusText`，响应头则通过 `event.res.headers` 设置。升级指南中提供了[差异对照表](https://nuxt.zhcndoc.com/docs/getting-started/upgrade#moving-to-nuxtserver)。

本次发布没有任何内容\_要求\_您迁移。但如果您希望在 Nuxt 5 到来之前让服务端代码具备可移植性，这就是最佳方式。

::read-more{to="https://nuxt.zhcndoc.com/docs/guide/going-further/server-imports"}
阅读服务端导入指南。
::

## 🔐 `appSecret` 和会话

感谢 [@onmax](https://github.com/onmax)，Nuxt 现在有了应用根密钥：`runtimeConfig.appSecret`，通过 `NUXT_APP_SECRET` 设置（[#35874](https://github.com/nuxt/nuxt/pull/35874)）。模块和服务端功能使用 `deriveSecret(purpose)` 从中派生各自的密钥，因此您只需配置这一个密钥。

```bash
openssl rand -base64 32
```

在开发环境中，如果未配置密钥，Nuxt 会生成并持久化一个，并在首次使用派生密钥时发出警告。构建过程不会生成密钥。

首个使用它的功能是 `nuxt/server` 中的一组会话工具（[#36358](https://github.com/nuxt/nuxt/pull/36358)）。会话使用 [iron](https://github.com/brc-dd/iron-webcrypto) 密封到 cookie 中，因此无需配置服务端存储：

```ts [server/api/visits.ts]
import { defineEventHandler, useSession } from 'nuxt/server'

export default defineEventHandler(async (event) => {
  const session = await useSession<{ visits: number }>(event)
  await session.update(data => ({ visits: (data.visits ?? 0) + 1 }))
  return { visits: session.data.visits }
})
```

::note
提醒一下，以 `app` 为前缀的运行时配置键（`runtimeConfig.app`、`runtimeConfig.appSecret`）为 Nuxt 保留。
::

## 🎯 重构类型化 `$fetch`

`$fetch` 和 `useFetch` 早已能够从服务端路由获取类型。此前这些类型来自 Nitro 的 `InternalApi` 接口，当路由超过几百个时，就会触及 TypeScript 的实例化限制：

```
error TS2589: Type instantiation is excessively deep and possibly infinite.
```

我们基于 [`fetchdts`](https://github.com/danielroe/fetchdts) 重构了类型化 fetch（[#36238](https://github.com/nuxt/nuxt/pull/36238)）。Nuxt 将服务端路由编译成路由树，为静态路径建立精确匹配表，并生成针对您的路由集合优化的访问器。现在解析开销随调用位置数量增长，而非随路由数量增长：

| 路由数             | 之前                            | 之后              |
| --------------- | ----------------------------- | --------------- |
| 100             | 1,397,361 次实例化 / 0.77s        | 51,558 / 0.26s  |
| 300             | 5,774,425 / 3.49s (`TS2589`)  | 51,558 / 0.16s  |
| 1000            | 12,831,467 / 7.44s (`TS2589`) | 51,558 / 0.20s  |
| 3000（200 个调用位置） | 71,875,148 / 53.63s（`TS2589`） | 101,678 / 0.62s |

同样测试中的峰值内存从 946 MB 降至 140 MB。🔥

此外，路由集合还携带每个处理程序验证的 `body`、`query` 和 `headers`，因此调用时也会根据它们进行检查：

```ts
// server/api/users.post.ts validates { title: string, count: number }
await $fetch('/api/users', { method: 'post', body: { title: 'a', count: 1 } })
await $fetch('/api/users', { method: 'post', body: { title: 'a', count: 'no' } })
//                                                                ^ not assignable to number
await $fetch('/api/users', { method: 'post' })
//           ^ body is required
```

![请求体结构错误的 $fetch 调用产生类型错误](https://nuxt.zhcndoc.com/assets/blog/v4-6/typed-fetch-error-light.png){.dark:hidden}
![请求体结构错误的 $fetch 调用产生类型错误](https://nuxt.zhcndoc.com/assets/blog/v4-6/typed-fetch-error-dark.png){.hidden.dark:block}

在 Nuxt 4 中，这项功能需要主动启用，因为类型推断存在一些细微变化（例如处理程序返回的 `Date` 在调用位置会变为 `string`），手写的 `ServerRoutes` 扩展也需要少量改写。在 Nuxt 5 中，它将默认启用。

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  experimental: {
    routeTypedFetch: true,
  },
})
```

此外，还新增了 `experimental.strictRouteTypes` 选项，用于拒绝调用不存在的路径（否则这些调用只会返回 `unknown`），以及一种 `'isomorphic'` 模式。如果您希望从 Vue 渲染器中以类型安全的方式通过 `$fetch` 请求页面，该模式也会将页面标记为 `GET` 路由。

::read-more{to="https://nuxt.zhcndoc.com/docs/guide/going-further/experimental-features#routetypedfetch"}
阅读更多关于 `routeTypedFetch` 的内容。
::

## 🐛 更好的开发错误体验

开发环境中的服务端错误过去是这样的：

```
ReferenceError: foo is not defined
    at Object.<anonymous> (/_nuxt/app/pages/index.vue:1:1)
```

其中没有源码位置或代码片段，我们渲染的 Youch iframe 也无法显示您自己源码中的代码片段。现在这两个问题都已修复（[#36258](https://github.com/nuxt/nuxt/pull/36258)、[nuxt/cli#1518](https://github.com/nuxt/cli/pull/1518)）。

开发环境的 SSR 堆栈跟踪现在会在任何代码读取错误之前完成映射，Youch 浮层也已被 [`my-bad`](https://github.com/danielroe/my-bad) 替代。它会在应用自身的错误页面中显示为浮层（当应用无法渲染错误页时，则作为独立页面），并展示映射后的堆栈跟踪和源码代码片段。

![my-bad 错误浮层，显示映射后的堆栈跟踪和代码片段](https://nuxt.zhcndoc.com/assets/blog/v4-6/my-bad-ssr-expanded-light.png){.dark:hidden}
![my-bad 错误浮层，显示映射后的堆栈跟踪和代码片段](https://nuxt.zhcndoc.com/assets/blog/v4-6/my-bad-ssr-expanded-dark.png){.hidden.dark:block}

其中有一个**复制错误**按钮，支持多种格式，包括可以直接交给 agent 的提示词：

![my-bad 复制菜单，支持 Markdown、agent 提示词和 JSON 格式](https://nuxt.zhcndoc.com/assets/blog/v4-6/my-bad-ssr-copymenu-dark.png)

同样的报告也会输出到终端：

![终端中渲染的 my-bad 错误报告](https://nuxt.zhcndoc.com/assets/blog/v4-6/my-bad-terminal-light.png){.dark:hidden}
![终端中渲染的 my-bad 错误报告](https://nuxt.zhcndoc.com/assets/blog/v4-6/my-bad-terminal-dark.png){.hidden.dark:block}

在 Nuxt CLI v4 中，错误还会通过 CLI 层的统一实时通道处理，该通道能在 worker 重启后继续存在。`nuxt.config.ts` 中的语法错误（或其他致命启动错误）会作为页面呈现，修复后页面会重新加载。每个错误只渲染一次，而不会在经过的每一层都重复渲染。

![my-bad 显示 nuxt.config.ts 中无法加载模块的错误页面](https://nuxt.zhcndoc.com/assets/blog/v4-6/my-bad-fatal-light.png){.dark:hidden}
![my-bad 显示 nuxt.config.ts 中无法加载模块的错误页面](https://nuxt.zhcndoc.com/assets/blog/v4-6/my-bad-fatal-dark.png){.hidden.dark:block}

我们正与 [@atinux](https://github.com/atinux)、[@HugoRCD](https://github.com/HugoRCD) 和 [@antfu](https://github.com/antfu) 合作，进一步改善这些页面。

## 🎨 全新的加载界面、404 和错误页面

[@HugoRCD](https://github.com/HugoRCD) 重新设计了开发服务器启动时的加载界面。现在它是一个 WebGL2 粒子场，在 Nuxt 组合标识后方勾勒出山脉（[#36178](https://github.com/nuxt/nuxt/pull/36178)），只使用一个着色器和一次绘制调用。不支持 WebGL2 时会回退为静态组合标识，启用 `prefers-reduced-motion` 时动画会停止。试着将鼠标悬停在上面。🏔️

<!-- TODO: past posts host video on Cloudinary; consider uploading these mp4s (3.6 MB + 5.9 MB) there rather than committing them -->

::themed-video
```yaml [props]
light: /assets/blog/v4-6/loading-screen-light.mp4
light-poster: /assets/blog/v4-6/loading-screen-light.png
dark: /assets/blog/v4-6/loading-screen-dark.mp4
dark-poster: /assets/blog/v4-6/loading-screen-dark.png
controls: true
autoplay: true
loop: true
class: rounded-lg
```
::

Hugo 还为内置的 404 和错误页面采用了中性配色与更轻的字体（[#36255](https://github.com/nuxt/nuxt/pull/36255)），[@MirkoJa](https://github.com/MirkoJa) 则为 404 页面添加了返回按钮（[#35688](https://github.com/nuxt/nuxt/pull/35688)）。

![带有返回按钮的新 404 页面](https://nuxt.zhcndoc.com/assets/blog/v4-6/404-page-light.png){.dark:hidden}
![带有返回按钮的新 404 页面](https://nuxt.zhcndoc.com/assets/blog/v4-6/404-page-dark.png){.hidden.dark:block}

![新的错误页面](https://nuxt.zhcndoc.com/assets/blog/v4-6/error-page-prod-light.png){.dark:hidden}
![新的错误页面](https://nuxt.zhcndoc.com/assets/blog/v4-6/error-page-prod-dark.png){.hidden.dark:block}

通过 `experimental.prerenderErrorPages`，您可以将错误页面预渲染为真正的 HTML（`404.html`，或您传入的任意状态码），而非空的 SPA 外壳（[#35193](https://github.com/nuxt/nuxt/pull/35193)，感谢 [@Flo0806](https://github.com/Flo0806)）。

## ⚡️ Vue Vapor 支持

Nuxt 现在支持 Vue 3.6 的 [Vapor Mode](https://github.com/vuejs/core/releases/tag/v3.6.0-rc.1#about-vapor-mode) 互操作模式（[#35759](https://github.com/nuxt/nuxt/pull/35759)）。应用根组件仍使用虚拟 DOM，您可以通过 `<script setup>` 上的 `vapor` 属性，让单个组件或页面启用 Vapor：

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  vue: {
    vapor: true,
  },
})
```

```vue [app/pages/index.vue]
<script setup vapor lang="ts">
const count = ref(0)
</script>

<template>
  <button @click="count++">
    count is {{ count }}
  </button>
</template>
```

路由、`useAsyncData`、布局和大多数内置组件无需修改即可使用。为此，我们让自动导入加载器、`useAsyncData`、`definePageMeta` 和插槽检查支持 Vapor，向 Vue 上游提交了一些修复，并添加了 Vapor 测试套件来跟踪支持情况。

::note
这需要 Vue `^3.6.0-rc.2` 或更新版本。请查看[已知限制](https://nuxt.zhcndoc.com/docs/guide/concepts/vuejs-development#known-limitations)，并先在新项目中尝试。
::

## 🔮 现在就体验 Nuxt 5 功能

Nuxt 5 的大多数新功能已经包含在 4.6 中，部分默认启用，其他可通过选项开启。`future.compatibilityVersion: 5` 可以一次性启用 Nuxt 5 的默认行为，您仍可分别切换每一项。

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 5,
  },
})
```

本次发布将以下内容加入该选项：

- 类型化页面（`experimental.typedPages`）
- 上文介绍的类型化 `$fetch`（`experimental.routeTypedFetch`）
- 区分大小写的路由，与 Nitro 保持一致（[#35650](https://github.com/nuxt/nuxt/pull/35650)，感谢 [@Mateleo](https://github.com/Mateleo)）
- `experimental.navigateToEarlyReturn`：在 `<script setup>` 中调用 `navigateTo` 会跳过其余 setup 代码，因此重定向和 404 不会因数据缺失而抛出错误
- 在构建时提取可序列化的 `definePageMeta` 键（`experimental.extractSerializablePageMeta`、[#35919](https://github.com/nuxt/nuxt/pull/35919)）
- `experimental.payloadExtraction: 'client'`
- 生成的 tsconfig 中不再包含 `baseUrl`（[#36040](https://github.com/nuxt/nuxt/pull/36040)，感谢 [@oritwoen](https://github.com/oritwoen)）
- 内联错误渲染（`experimental.inlineErrorRendering`）：服务端渲染失败时，在同一请求中通过普通 try/catch 渲染 `error.vue`，而不是向 `/__nuxt_error` 发起内部请求，因此已设置的响应头和 cookie 会保留，错误渲染不再二次经过 Nitro 中间件和路由规则，`render:html` 也会使用原始事件触发（[#36399](https://github.com/nuxt/nuxt/pull/36399)）
- 规范化页面名称、`clearNuxtState` 重置为默认值，以及 `experimental.watcher: 'builder'`
- 不再自动导入仅服务端可用的 head 组合式函数（`useServerHead`、`useServerHeadSafe` 和 `useServerSeoMeta`）

升级指南列出了[该选项在 Nuxt 4 中具体改变的行为](https://nuxt.zhcndoc.com/docs/getting-started/upgrade#testing-nuxt-5)。

## 🧪 实验性功能：`@nuxt/vite-server`

从 v4.2 开始，`server.builder` 就已支持配置。本次发布新增了第二个服务端构建器：`@nuxt/vite-server`，仅使用 Vite 构建 Nuxt 应用（[#36218](https://github.com/nuxt/nuxt/pull/36218)、[#36279](https://github.com/nuxt/nuxt/pull/36279)、[#36288](https://github.com/nuxt/nuxt/pull/36288)）。

只需以下配置即可使用：

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  server: {
    builder: 'vite', // 'nitro' is the default
  },
})
```

它可以生成仅客户端的 SPA、带有小型 Node 入口的服务端渲染应用、用于自带服务器的平台的符合 Web 标准的 `fetch` 处理程序（[Cloudflare Workers](https://developers.cloudflare.com/workers/vite-plugin/)、[Netlify](https://github.com/netlify/framework-adapters/tree/main/packages/vite-plugin) 和 [universal deploy](https://github.com/universal-deploy/universal-deploy) 都有端到端示例），也能通过 `nuxt generate` 生成完全静态的输出。

目前，这有助于保持 Nuxt 代码的服务器无关性，落实 `nuxt/server` 背后的约定，并为提供部署目标的 Vite 插件提供基础。它并不具备 Nitro 的全部功能（没有存储、缓存、任务或服务端插件），我们预计大多数应用仍将继续使用 Nitro。**Nitro 仍是默认选项。**

::warning
这是高度实验性的功能，API 将会变化。`'nitro'` 和 `'vite'` 分别是 `@nuxt/nitro-server` 和 `@nuxt/vite-server` 的新简写。
::

## 🚀 性能

以下是在我们的基准测试机器上，4.6 与 4.5.2 的对比结果（arm64 Linux、Node.js 24.15，取五次运行的中位数）：

|                                         | v4.5.2    | v4.6.0    |          |
| --------------------------------------- | --------- | --------- | -------- |
| `@nuxt/kit` 安装体积                        | 6.4 MB    | 2.1 MB    | **-67%** |
| `@nuxt/kit` 传递依赖数量                      | 36        | 22        | **-39%** |
| `nuxt build`，初始项目                       | 4.4 s     | 3.6 s     | **-18%** |
| `nuxt build`，200 个页面 / 200 个组件 / 50 个路由 | 11.6 s    | 10.3 s    | **-11%** |
| SSR 吞吐量，包含 300 个 `<NuxtLink>` 的页面       | 110 req/s | 140 req/s | **+26%** |

初始应用的开发服务器启动速度（从进程启动到首个 HTML）提升约 12%，第二次请求的耗时大约减半。CLI 主版本也在同时升级，因此并非所有提升都来自 Nuxt。大型应用的启动速度与 4.5.2 大致相同。

`<NuxtLink>` 的数据来自 [#36015](https://github.com/nuxt/nuxt/pull/36015)。内部链接现在会在服务端渲染为普通 `<a>`，不使用 `useLink`，也不创建响应式状态。渲染 200 个链接的耗时从 1.36ms 降至 0.57ms，比直接使用 `<RouterLink>` 还快。

启用 `experimental.early404`（[#36117](https://github.com/nuxt/nuxt/pull/36117)）后，页面路由会在构建时编译成静态匹配器。无法匹配任何页面的请求会跳过 Vue 应用创建，以及插件和中间件执行。在一个包含 30 个页面、每次渲染约需 23ms 初始化工作的应用中，JSON 404 的耗时从 37.1ms 降至 0.3ms。

模板现在可以声明哪些变化会使其失效（[#35875](https://github.com/nuxt/nuxt/pull/35875)）。过去，每次文件变化都会重新生成所有模板。现在，编辑组件不会重新生成 49 个核心模板中的任何一个，`builder:watch` 钩子的处理耗时也从 36ms 降至 0.6ms。

`useCookie` 每个请求只解析一次 cookie 请求头，在客户端则每个微任务只解析一次（[#36114](https://github.com/nuxt/nuxt/pull/36114)）。这也意味着，在 SSR 期间由插件设置的 cookie，可以被页面中稍后调用的 `useCookie` 读取。

一些较小的变化：`ssr: false` 页面的代码会从服务端产物中摇树移除（[#35836](https://github.com/nuxt/nuxt/pull/35836)，感谢 [@Austin1serb](https://github.com/Austin1serb)），不再向浏览器发送 `unctx`，仅有一个 `app.config` 时会跳过 `defu`（[#36371](https://github.com/nuxt/nuxt/pull/36371)），Vite 会先预热服务端模块图再预热客户端，在预热时遍历客户端模块图，并优先响应您的首次导航（[#36154](https://github.com/nuxt/nuxt/pull/36154)、[#35870](https://github.com/nuxt/nuxt/pull/35870)、[#36412](https://github.com/nuxt/nuxt/pull/36412)），`@nuxt/kit` 则移除了 `c12`、`untyped`、`confbox`、`pkg-types`、`ufo` 和 `mlly`，`jiti` 和 `giget` 现为可选的 peer dependency。

### 更轻量的 Payload

`useAsyncData` 和 `useFetch` 接受 `serialize: false`，使数据不进入 payload（[#35779](https://github.com/nuxt/nuxt/pull/35779)）。这主要适用于永不水合的组件，`experimental.stripNeverHydratedData` 会在 `hydrate-never` 组件树中自动应用它。

```ts
const { data } = await useFetch('/api/stats', { serialize: false })
```

在开发环境中，当页面的 payload 超过 100 kB，或使用 `noScripts` 渲染的路由依赖客户端 JavaScript 时，Nuxt 现在会发出警告。这些页面也会保留非脚本资源提示和样式（[#35803](https://github.com/nuxt/nuxt/pull/35803)、[#36356](https://github.com/nuxt/nuxt/pull/36356)、[#36359](https://github.com/nuxt/nuxt/pull/36359)）。`<NuxtLink>` 还会预取服务端页面岛，[@atinux](https://github.com/atinux) 为预取提示增加了节流和优先级，避免包含大量链接的页面占满网络（[#36261](https://github.com/nuxt/nuxt/pull/36261)、[#36324](https://github.com/nuxt/nuxt/pull/36324)）。在此基础上，路由代码块、布局、中间件、payload、岛和资源提示现在都通过同一个客户端预取调度器处理，具有按类型设置的并发上限、按键去重，以及离开页面时取消进行中任务的能力（[#36391](https://github.com/nuxt/nuxt/pull/36391)）。

## 🧩 `useFetch` 和 `useAsyncData` 的附加功能

[@cernymatej](https://github.com/cernymatej) 为 `createUseFetch` 和 `createUseAsyncData` 工厂函数添加了 `addons` 选项（[#35797](https://github.com/nuxt/nuxt/pull/35797)）。附加功能可以声明自定义调用选项、调整合并后的选项、用中间件包装处理程序，并扩展组合式函数的返回值，还可以在任意多个自定义实例间复用。

```ts [app/composables/useApiFetch.ts]
const refreshOnFocus = defineUseFetchAddon({
  setup: (options: UseFetchAddonOptions<{ refreshOnFocus?: boolean }>) => {
    if (import.meta.server || !options.refreshOnFocus) { return }

    return (asyncData) => {
      const focused = useWindowFocus()
      watch(focused, focused => focused && asyncData.refresh())
      return { focused }
    }
  },
})

export const useApiFetch = createUseFetch({ baseURL: '/api', addons: [refreshOnFocus] })
```

```vue [app/pages/todos.vue]
<script setup lang="ts">
const { data, focused } = await useApiFetch('/todos', { refreshOnFocus: true })
</script>
```

这满足了 `useAsyncData` 和 `useFetch` 的一长串功能请求（聚焦时刷新、轮询、重试、身份验证请求头等），同时无需让核心组合式函数内置这些功能的具体策略。

::read-more{to="https://nuxt.zhcndoc.com/docs/api/utils/define-use-fetch-addon"}
阅读关于 `defineUseFetchAddon` 和 `defineUseAsyncDataAddon` 的内容。
::

## 🛠️ 开发体验

终端输出中的文件路径现在可以点击（[#35898](https://github.com/nuxt/nuxt/pull/35898)）。警告中提到的文件会链接到编辑器中的对应文件，如果已知行号，还会定位到相关行。

![终端堆栈跟踪中可点击的文件路径](https://nuxt.zhcndoc.com/assets/blog/v4-6/clickable-paths-stacktrace-light.png){.dark:hidden}
![终端堆栈跟踪中可点击的文件路径](https://nuxt.zhcndoc.com/assets/blog/v4-6/clickable-paths-stacktrace-dark.png){.hidden.dark:block}

在模板中将鼠标悬停在 `<NuxtLayout>` 或 `<NuxtLink>` 等内置组件上，现在会显示简短描述和文档链接（[#35701](https://github.com/nuxt/nuxt/pull/35701)，感谢 [@Ibochkarev](https://github.com/Ibochkarev)）。

<!-- NOTE for Daniel: this hover-docs image is a mock-up, not a real editor capture -->

![编辑器中 NuxtLink 的悬停文档](https://nuxt.zhcndoc.com/assets/blog/v4-6/ide-hover-docs-nuxt-link-light.png){.dark:hidden}
![编辑器中 NuxtLink 的悬停文档](https://nuxt.zhcndoc.com/assets/blog/v4-6/ide-hover-docs-nuxt-link-dark.png){.hidden.dark:block}

其他变化：

- 新增了顶层 `prerender` 选项，它是 `nitro.prerender` 的别名，与顶层的 `runtimeConfig` 和 `routeRules` 类似（[#32356](https://github.com/nuxt/nuxt/pull/32356)）。Nuxt 现在也会在存在对应顶层选项时提示您使用它们，因为这些选项可跨服务端构建器工作（[#36416](https://github.com/nuxt/nuxt/pull/36416)）。
- 使用 `<NuxtLink>` 链接到 `public/` 中的文件（或从 Nuxt Content 的 Markdown 中链接）不再需要 `external`：如果路由器中没有匹配路径，Nuxt 会改为整页加载，而不是渲染 404（[#36169](https://github.com/nuxt/nuxt/pull/36169)）。
- 在开发环境中重命名组件会刷新其导入，因此不会再看到指向旧文件的过期引用（[#36165](https://github.com/nuxt/nuxt/pull/36165)，感谢 [@oritwoen](https://github.com/oritwoen)）。
- 从 `node_modules` 安装的层，其依赖会由 Vite 预打包（[#36208](https://github.com/nuxt/nuxt/pull/36208)），符号链接的层目录则会解析到真实路径（[#36402](https://github.com/nuxt/nuxt/pull/36402)，感谢 [@silverbackdan](https://github.com/silverbackdan)）。
- `app/types/` 和 `server/types/` 会被纳入正确的 tsconfig，因此其中的环境类型和类型扩展能够被识别（[#35783](https://github.com/nuxt/nuxt/pull/35783)）。这项工作由 [@Flo0806](https://github.com/Flo0806) 完成，他还添加了可扩展的 `NuxtPageMeta` 接口，用于为 `NuxtPage.meta` 提供类型（[#34816](https://github.com/nuxt/nuxt/pull/34816)）。
- `components/` 内的 `(group)/` 文件夹不会计入组件名称（[#35699](https://github.com/nuxt/nuxt/pull/35699)，感谢 [@abaza738](https://github.com/abaza738)）。
- `useCookie` 的 `expires` 选项接受函数（[#35628](https://github.com/nuxt/nuxt/pull/35628)，感谢 [@DarlanPrado](https://github.com/DarlanPrado)）。
- 当 `public/` 文件遮蔽应用路由时，Nuxt 会发出警告（[#35674](https://github.com/nuxt/nuxt/pull/35674)，感谢 [@Norbiros](https://github.com/Norbiros)）。
- `typescript.tsConfig` 现在是所有生成的 tsconfig 的共享基线，`appTsConfig` 和 `serverTsConfig` 用于各上下文的覆盖配置（[#35697](https://github.com/nuxt/nuxt/pull/35697)，感谢 [@chairulakmal](https://github.com/chairulakmal)）。
- [@DamianGlowala](https://github.com/DamianGlowala) 从 `nuxt/app` 导出了 `$Fetch` 类型（[#35625](https://github.com/nuxt/nuxt/pull/35625)），并将 `ShallowRef` 添加到 Vue 自动导入预设（[#36266](https://github.com/nuxt/nuxt/pull/36266)）。

## 🧰 致模块作者

如果您维护的模块包含服务端代码，现在无需提升主版本，就能让它同时兼容 Nuxt 4 和 Nuxt 5。（我们也会在 Nuxt 4.6 发布后主动提交 PR，帮助模块为 Nuxt 5 做好准备。）

`addServerHandler`、`addDevServerHandler` 和 `addNitroPlugin` 接受按服务端 API 区分的变体映射（[#36317](https://github.com/nuxt/nuxt/pull/36317)），Nuxt 会选择最合适的一个：

```ts [module.ts]
addServerHandler({
  route: '/api/my-module/status',
  handler: {
    nuxt: resolve('./runtime/server/status'),
    nitro2: resolve('./runtime/server/status.legacy'),
  },
})
```

仅从 `nuxt/server` 导入的处理程序完全不需要 Nitro 2/3 变体（但需要 Nuxt 4.6+）。Nuxt 会读取文件的导入来判断它使用的 API，无法据此判断时，您可以声明 `meta.compatibility.server`。如果您的逻辑\_明确\_需要知道安装的 Nitro 版本，也可以使用 `getNitroVersion` 和 `hasNitroVersion`（[#36127](https://github.com/nuxt/nuxt/pull/36127)）。

::read-more{to="https://nuxt.zhcndoc.com/docs/guide/modules/server-compatibility"}
阅读服务端兼容性指南。
::

面向模块作者的其他新增功能：

- Nuxt 自身维护的可扩展服务端类型：`ServerTypes`、`ServerRoutes`、`AppRouteRules` 和 `NuxtRequestContext`（[#36293](https://github.com/nuxt/nuxt/pull/36293)）
- `deriveSecret`，从 `appSecret` 派生模块专属密钥
- `useTerminal`，用于显示提示、状态消息和任务进度，CLI 的开发面板可用时会在其中渲染（[#36162](https://github.com/nuxt/nuxt/pull/36162)）
- `module:before` 和 `module:done` 钩子，Nuxt CLI v4 用它们显示每个模块的初始化耗时（[#36173](https://github.com/nuxt/nuxt/pull/36173)）
- `onConfigResolved` 和 `diffNuxtConfig`，用于查看两次配置加载之间的变化（[#35853](https://github.com/nuxt/nuxt/pull/35853)）
- `ensureDependencyInstalled` 和 `getAddDependencyCommand`，使用用户的包管理器提供可选依赖（[#34554](https://github.com/nuxt/nuxt/pull/34554)）
- 模板的 `dependencies`，用于声明哪些变化会使模板失效（[#35875](https://github.com/nuxt/nuxt/pull/35875)）
- 跨 Nitro 版本的 `addServerImports`、`addServerImportsDir` 和 `addServerTemplate`，包含生成的服务端 tsconfig 和按版本区分的路由配置类型（[#36265](https://github.com/nuxt/nuxt/pull/36265)）
- `@nuxt/kit` 明确的公共 API（[#36074](https://github.com/nuxt/nuxt/pull/36074)），`@nuxt/schema` 现在是可选的 peer dependency
- 模块可以设置 `experimental.asyncContext`（[#36175](https://github.com/nuxt/nuxt/pull/36175)，感谢 [@cernymatej](https://github.com/cernymatej)）
- 通过 kit 添加的 Vite 插件在顶层注册（[#36037](https://github.com/nuxt/nuxt/pull/36037)），更多构建时警告使用[诊断代码](https://nuxt.zhcndoc.com/docs/errors)（[#36138](https://github.com/nuxt/nuxt/pull/36138)）
- 放宽 `@nuxt/kit` 的 peer dependency 版本范围（[#36417](https://github.com/nuxt/nuxt/pull/36417)），并允许在 Nitro 创建之前调用 `updateRuntimeConfig`，不再发出警告（[#36403](https://github.com/nuxt/nuxt/pull/36403)，感谢 [@Neekoras](https://github.com/Neekoras)）

## 🩹 修复与安全

[@oritwoen](https://github.com/oritwoen) 修复了服务端组件插槽中的作用域样式、重复的岛资源请求，以及延迟水合时重新挂载出现空白的问题（[#36047](https://github.com/nuxt/nuxt/pull/36047)、[#36048](https://github.com/nuxt/nuxt/pull/36048)、[#36051](https://github.com/nuxt/nuxt/pull/36051)）。[@hdwebpros](https://github.com/hdwebpros) 让 `useRequestFetch` 转发请求头（[#36180](https://github.com/nuxt/nuxt/pull/36180)），[@Askerka00](https://github.com/Askerka00) 修复了导航途中视图过渡被跳过的问题（[#35537](https://github.com/nuxt/nuxt/pull/35537)），[@Flo0806](https://github.com/Flo0806) 让变化后的自动导入来源先于其使用方重新扫描（[#33671](https://github.com/nuxt/nuxt/pull/33671)），[@onmax](https://github.com/onmax) 则保留了开发环境中的错误原因（[#35632](https://github.com/nuxt/nuxt/pull/35632)）。

其他修复涵盖水合和延迟获取期间被 await 的 `useAsyncData`（[#36124](https://github.com/nuxt/nuxt/pull/36124)、[#36301](https://github.com/nuxt/nuxt/pull/36301)）、`navigateTo` 的路径编码以及 `open` 配合 `baseURL` 的行为（[#36055](https://github.com/nuxt/nuxt/pull/36055)、[#36112](https://github.com/nuxt/nuxt/pull/36112)、[#36197](https://github.com/nuxt/nuxt/pull/36197)）、CSS 提取和内联样式，以及被中断的视图过渡（[#36314](https://github.com/nuxt/nuxt/pull/36314)）。

安全方面，内部错误路由只能由错误渲染访问，开发错误报告对远程访问方限制了范围，并且不会进入生产构建，未处理的错误数据也不再传给错误页面。详细内容请参阅发布说明。

## ⬆️ 升级

我们建议运行以下命令升级：

```sh
npx nuxt upgrade --dedupe
```

这会刷新您的 lockfile，并拉取 Nuxt 所依赖的最新依赖，包括 Nuxt CLI v4。

::note
本次发布需要 Node.js `^22.22.3 || ^24.15.0 || >=26.0.0`。
::

如果您希望让服务端代码具备可移植性，请阅读升级指南中的[迁移至 `nuxt/server`](https://nuxt.zhcndoc.com/docs/getting-started/upgrade#moving-to-nuxtserver)。

## 👉 完整发布说明

::read-more{icon="i-simple-icons-github" target="_blank" to="https://github.com/nuxt/nuxt/releases/tag/v4.6.0"}
阅读 Nuxt `v4.6.0` 的完整发布说明。
::

感谢每一位为本次发布做出贡献的人。💚


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
