---
title: "实验特性"
description: "启用 Nuxt 实验性功能以解锁新可能性。"
canonical_url: "https://nuxt.zhcndoc.com/docs/4.x/guide/going-further/experimental-features"
---
# 实验特性

> 启用 Nuxt 实验性功能以解锁新可能性。

Nuxt 包含可以在配置文件中启用的实验性功能。

在内部，Nuxt 使用 `@nuxt/schema` 来定义这些实验性功能。有关更多信息，请参阅 [API 文档](https://nuxt.zhcndoc.com/docs/4.x/guide/going-further/experimental-features)或[源代码](https://github.com/nuxt/nuxt/blob/main/packages/schema/src/config/experimental.ts)。

<note>

请注意，这些功能是实验性的，未来可能会被移除或修改。

</note>

## alwaysRunFetchOnKeyChange

当 key 发生变化时，是否运行 `useFetch`，即便其设置为 `immediate: false` 且尚未被触发。

如果 `immediate: true` 或已被触发，`useFetch` 和 `useAsyncData` 在 key 更改时将始终运行。

此标志默认禁用，但您可以启用此功能：

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

## appManifest

使用应用清单让客户端遵循路由规则。

此标志默认启用，但你可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    appManifest: false,
  },
})
```

## asyncContext

启用原生异步上下文，使其可在 Nuxt 和 Nitro 中被嵌套的 composable 访问。这使得在异步 composable 中使用 composable 成为可能，并减少出现 `Nuxt instance is unavailable` 错误的概率。

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

<read-more to="https://github.com/nuxt/nuxt/pull/20918" icon="i-simple-icons-github" target="_blank">

在 GitHub 拉取请求中查看完整说明。
:::

## asyncEntry

为 Vue 包生成异步入口点，以利于支持模块联邦（module federation）。

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

## externalVue

在构建时将 `vue`、`@vue/*` 和 `vue-router` 外部化。

此标志默认启用，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    externalVue: false,
  },
})
```

<warning>

此功能很可能在不久的将来被移除。

</warning>

## extractAsyncDataHandlers

从 `useAsyncData` 和 `useLazyAsyncData` 调用中提取处理函数到单独的块，以提高代码拆分和缓存效率。

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

此功能将内联处理函数转换为动态导入的代码块：

```vue
<!-- 转换前 -->
<script setup>
const { data } = await useAsyncData('user', async () => {
  return await $fetch('/api/user')
})
</script>
```

```vue
<!-- 转换后 -->
<script setup>
const { data } = await useAsyncData('user', () =>
  import('/generated-chunk.js').then(r => r.default()),
)
</script>
```

这种转变的好处在于，我们可以将数据获取逻辑分离出来，同时仍然允许在需要时加载代码。

<important>

此功能仅建议用于具有有效负载提取的 **静态构建**，并且数据在运行时不需要重新获取的情况。

</important>

## emitRouteChunkError

在加载 vite/webpack chunk 时发生错误时发出 `app:chunkError` 钩子。默认行为是在导航到新路由时，当 chunk 无法加载时重新加载新路由。

默认情况下，Nuxt 在导航到新路由时，如果 chunk 无法加载也会执行路由重载（`automatic`）。

设置为 `automatic-immediate` 时，Nuxt 会在 chunk 加载失败时立即重新加载当前路由（而不是等待导航）。这对并非由导航触发的 chunk 错误很有用，例如 Nuxt 应用无法加载[懒加载组件](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/components#dynamic-imports)时。此行为的一个潜在缺点是可能导致不必要的重新加载，例如应用并不需要导致错误的 chunk 时。

您可以将其设置为 `false` 来禁用自动处理，或设置为 `manual` 以手动处理 chunk 错误。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    emitRouteChunkError: 'automatic', // 或 'automatic-immediate', 'manual' 或 false
  },
})
```

## 强制模块兼容性

当 Nuxt 模块不兼容时，是否应抛出错误并阻止加载。

此功能默认禁用。

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

## restoreState

允许在 chunk 错误或手动调用 [`reloadNuxtApp()`](https://nuxt.zhcndoc.com/docs/4.x/api/utils/reload-nuxt-app) 后重新加载页面时，从 `sessionStorage` 恢复 Nuxt 应用状态。

为了避免水合（hydration）错误，此操作仅在 Vue 应用挂载后应用，这意味着初次加载时可能会有闪烁现象。

<important>

启用此功能前请仔细考虑，因为它可能导致意外行为；同时，建议为 [`useState`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-state) 提供显式的 key，因为自动生成的 key 在不同构建版本之间可能不匹配。

</important>

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

## inlineRouteRules

使用 [`defineRouteRules`](https://nuxt.zhcndoc.com/docs/4.x/api/utils/define-route-rules) 在页面级别定义路由规则。

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

根据页面的 `path` 创建匹配的路由规则。

<read-more to="https://nuxt.zhcndoc.com/docs/4.x/api/utils/define-route-rules" icon="i-lucide-square-function">

阅读更多有关 `defineRouteRules` 工具函数的信息。

</read-more>

<read-more to="https://nuxt.zhcndoc.com/docs/4.x/guide/concepts/rendering#hybrid-rendering" icon="i-lucide-medal">



</read-more>

## renderJsonPayloads

允许以支持复原复杂类型的方式渲染 JSON 负载。

此标志默认已启用，但你可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    renderJsonPayloads: false,
  },
})
```

## noVueServer

在 Nitro 中禁用 Vue 服务端渲染器端点。

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

## parseErrorData

在渲染服务器错误页面时是否解析 `error.data`。

此标志默认启用，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    parseErrorData: false,
  },
})
```

## payloadExtraction

控制 payload 数据在预渲染（prerendered）和缓存（ISR/SWR）页面中如何交付。

- `'client'` - 初始服务端渲染时，Payload 会内联在 HTML 中，并在客户端导航时提取到 `_payload.json` 文件中。
- `true` - 初始服务端渲染和客户端导航都会将 Payload 提取到单独的 `_payload.json` 文件中。
- `false` - 完全禁用 Payload 提取。Payload 始终以内联形式包含在 HTML 中，并且不会生成 `_payload.json` 文件。

默认值为 `true`；当设置了 `compatibilityVersion: 5` 时，默认值为 `'client'`。当设置了 `ssr: false` 时，会强制为 `false`。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    payloadExtraction: 'client',
  },
})
```

<read-more to="https://nuxt.zhcndoc.com/docs/4.x/getting-started/prerendering#payload-extraction">

阅读更多有关 payload 提取及各模式所带来影响的信息。

</read-more>

## clientNodePlaceholder

使用注释节点（`<!--placeholder-->`）替代 `<div>` 元素，作为服务器端渲染（SSR）期间仅客户端组件的占位符。

启用后，`.client.vue` 组件以及 `createClientOnly()` 包装器将在服务器上渲染 HTML 注释，而不是空的 `<div>`。这修复了一个 Vue hydration 问题：当占位 `<div>` 和实际组件根节点共享相同的标签名时，可能导致作用域样式未被应用。

<warning>

启用此选项意味着传递给 `.client.vue` 组件的属性（`class`、`style` 等）将不会出现在 SSR 的 HTML 中。如果你需要带样式的占位以防止布局抖动，请使用带 `#fallback` 插槽的 `<ClientOnly>`。

</warning>

当 `future.compatibilityVersion` 设置为 `5` 或更高时启用此标志，但你也可以显式启用：

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

## serverPathFallback

将与页面路由不匹配的客户端导航作为完整文档加载，以便服务器可以返回 `public/` 中的文件、服务器路由或其 404 页面。启用此功能后，点击 `<NuxtLink to="/brochure.pdf">` 和 `<NuxtLink to="/rss.xml">` 时的效果与完整加载页面时相同。

如果当前文档已经是针对该路径提供的，则不会重新加载该路径，因此对于将未知路径响应为 SPA 回退的主机，会渲染客户端 404 页面。

此标志默认启用，但你可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    serverPathFallback: false,
  },
})
```

启用 `hashMode` 时，此选项不起作用。

## early404

对于路径无法匹配任何页面路由的请求，提前返回 404 错误，而无需在服务器上加载 Vue 应用、其插件或中间件。

页面路由（包括别名）会在构建时编译为静态路由匹配器，并且传入的请求会在服务端渲染开始前与其进行匹配。无法匹配任何页面的请求会完全跳过应用加载，直接进入错误页面。

没有 `Accept: text/html` 标头的请求（API 客户端、大多数扫描器）会收到 JSON 错误，而完全不会加载应用。HTML 请求仍会进行服务端渲染以显示错误页面。覆盖该路径的 [`cache` 路由规则](https://nuxt.zhcndoc.com/docs/4.x/guide/concepts/rendering#hybrid-rendering)也会在 GET/HEAD 未命中时通过 `Cache-Control` 标头公开其 `maxAge`，从而让 CDN 缓存对未知路径的重复请求。

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

<warning>

此功能需要显式启用，因为它可能会破坏依赖运行时路由的应用：

- 在插件中通过 `router.addRoute()` 动态添加页面。为尽早发现此问题，启用此选项时，`addRoute` 会从 [`useRouter`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-router) 返回的路由器类型中移除。
- 将未知路径重定向到现有页面的路由中间件

在开发环境中、启用 `hashMode` 时、根级捕获所有页面（例如 `pages/[...slug].vue`）匹配每个路径时，以及自定义 `app/router.options` 文件可能修改 `routes` 时，此选项会自动禁用（默认导出是不带 `routes` 键的普通对象的文件仍然兼容）。

</warning>

## clientFallback

启用实验性的 [`<NuxtClientFallback>`](https://nuxt.zhcndoc.com/docs/4.x/api/components/nuxt-client-fallback) 组件，以便在 SSR 出错时在客户端渲染内容。

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

## crossOriginPrefetch

使用 Speculation Rules API 启用跨域预取（cross-origin prefetch）。

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

<read-more to="https://wicg.github.io/nav-speculation/prefetch.html" icon="i-simple-icons-w3c" target="_blank">

阅读有关 Speculation Rules API 的更多信息。

</read-more>

## viewTransition

启用与客户端路由器的 View Transition API 集成。

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

你也可以传入一个对象来配置[视图过渡类型](https://nuxt.zhcndoc.com/docs/4.x/getting-started/transitions#view-transition-types)，从而根据导航类型使用不同的 CSS 动画：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    viewTransition: {
      enabled: true,
      types: ['slide'],
    },
  },
})
```

<link-example target="_blank" to="https://stackblitz.com/edit/nuxt-view-transitions?file=app.vue">



</link-example>

<read-more to="https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API" icon="i-simple-icons-mdnwebdocs" target="_blank">

了解有关 View Transition API 的更多信息。

</read-more>

<read-more to="https://developer.chrome.com/blog/view-transitions-update-io24" icon="i-simple-icons-google" target="_blank">

了解有关 **View Transition API** 的更多信息。

</read-more>

## writeEarlyHints

在使用 Node 服务器时启用写入 early hints。

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

## 组件岛（componentIslands）

启用实验性的组件岛支持，包括 [`<NuxtIsland>`](https://nuxt.zhcndoc.com/docs/4.x/api/components/nuxt-island) 和 `.island.vue` 文件。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    componentIslands: true, // 也可为 false 或 'local+remote'
  },
})
```

<read-more to="https://nuxt.zhcndoc.com/docs/4.x/guide/concepts/server-components">



</read-more>

<note>

对 [`<NuxtLink>`](https://nuxt.zhcndoc.com/docs/4.x/api/components/nuxt-link) 等非 SFC 组件跳过 `nuxt-client`。请参阅[使用 `nuxt-client` 进行选择性水合](https://nuxt.zhcndoc.com/docs/4.x/guide/concepts/server-components#selective-hydration-with-nuxt-client)。

</note>

<read-more to="https://github.com/nuxt/nuxt/issues/19772" icon="i-simple-icons-github" target="_blank">

你可以在 GitHub 上关注服务器组件的路线图。

</read-more>

## localLayerAliases

解析位于某个层中的 `~`、`~~`、`@` 和 `@@` 别名，并将其相对于该层的源目录和根目录进行解析。

此标志默认启用，但你可以将其禁用：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    localLayerAliases: false,
  },
})
```

## typedPages

启用新的实验性类型化路由。

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

开箱即用，它将为 [`navigateTo`](https://nuxt.zhcndoc.com/docs/4.x/api/utils/navigate-to)、[`<NuxtLink>`](https://nuxt.zhcndoc.com/docs/4.x/api/components/nuxt-link)、[`router.push()`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-router) 等启用类型化用法。

你甚至可以通过在页面中使用 `const route = useRoute('route-name')` 来获得类型化的 params。

<video-accordion title="观看 Daniel Roe 讲解 Nuxt 中类型安全路由" video-id="SXk-L19gTZk">



</video-accordion>

## 监视器

设置将用作 Nuxt 监视服务的替代监视器。

Nuxt 默认使用 `chokidar-granular`，它会忽略被排除在监视之外的顶级目录（例如 `node_modules` 和 `.git`）。

你可以将其设置为 `parcel` 以使用 `@parcel/watcher`，这在大型项目或 Windows 平台上可能会提高性能。

你也可以将其设置为 `chokidar` 来监视源目录中的所有文件。

将其设为 `'builder'` 以复用当前构建器自身的文件监视器（例如 Vite 的 `server.watcher`），而不是启动第二个监视器。这会减少开发模式下活动的文件监视器数量，并且在 `future.compatibilityVersion` 为 `5` 时会成为默认值。如果当前构建器没有实现自己的监视器（目前是 webpack 和 rspack），Nuxt 会记录警告并回退到默认选择。

将其设为 `'builder'` 以复用当前构建器自身的文件监视器（例如 Vite 的 `server.watcher`），而不是启动第二个监视器。这会减少开发模式下活动的文件监视器数量，并且在 `future.compatibilityVersion` 为 `5` 时会成为默认值。如果当前构建器没有实现自己的监视器（目前是 webpack 和 rspack），Nuxt 会记录警告并回退到默认选择。

将其设为 `'builder'` 以复用当前构建器自身的文件监视器（例如 Vite 的 `server.watcher`），而不是启动第二个监视器。这会减少开发模式下活动的文件监视器数量，并且在 `future.compatibilityVersion` 为 `5` 时会成为默认值。如果当前构建器没有实现自己的监视器（目前是 webpack 和 rspack），Nuxt 会记录警告并回退到默认选择。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    watcher: 'chokidar-granular', // 也可以使用 'chokidar'、'parcel' 或 'builder'
  },
})
```

## sharedPrerenderData

Nuxt 会自动在预渲染的页面之间共享 payload *数据*。当预渲染使用 `useAsyncData` 或 `useFetch` 且在不同页面中获取相同数据时，这可以显著提高性能。

如果需要，您可以禁用此功能。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    sharedPrerenderData: false,
  },
})
```

<video-accordion title="Alexander Lichter 讲解实验性 sharedPrerenderData 的视频" video-id="1jUupYHVvrU">



</video-accordion>

启用此功能时特别重要的是确保您的数据的任何唯一键总是可解析为相同的数据。例如，如果您在动态页面中使用 `useAsyncData` 来获取与特定页面相关的数据，则应提供一个唯一匹配该数据的键。（`useFetch` 应会为您自动做到这一点。）

```ts
// 这在动态页面（例如 `[slug].vue`）中不安全，因为路由 slug 会影响获取的数据
// 但 Nuxt 因为不反映在 key 中，因此无法识别差异。
const route = useRoute()
const { data } = await useAsyncData(async (_nuxtApp, { signal }) => {
  return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
})
// 相反，您应使用一个唯一标识所获取数据的 key。
const { data } = await useAsyncData(route.params.slug, async (_nuxtApp, { signal }) => {
  return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
})
```

## clientNodeCompat

启用此功能后，Nuxt 将在客户端构建中使用 [`unenv`](https://github.com/unjs/unenv) 自动为 Node.js 导入提供 polyfill。

<note>

要使像 `Buffer` 这样的全局变量在浏览器中工作，您需要手动注入它们。

```ts
import { Buffer } from 'node:buffer'

globalThis.Buffer ||= Buffer
```

</note>

## scanPageMeta

Nuxt 在构建时向模块公开在 `definePageMeta` 中定义的一些路由元数据（特别是 `alias`、`name`、`path`、`redirect`、`props` 和 `middleware`）。

这仅适用于静态值或字符串/数组，而不适用于变量或条件赋值。有关更多信息和上下文，请参阅[原始问题](https://github.com/nuxt/nuxt/issues/24770)。

默认情况下，页面元数据仅在 `pages:extend` 中所有路由注册完成后才会被扫描。然后会调用另一个钩子 `pages:resolved`。

如果此功能在您的项目中造成问题，您可以禁用它。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    scanPageMeta: false,
  },
})
```

## cookieStore

启用 CookieStore 支持以监听 cookie 更新（如果浏览器支持）并刷新 `useCookie` 的 ref 值。

此标志默认启用，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    cookieStore: false,
  },
})
```

<read-more to="https://developer.mozilla.org/en-US/docs/Web/API/CookieStore" icon="i-simple-icons-mdnwebdocs" target="_blank">

阅读有关 CookieStore 的更多信息。
:::

## buildCache

基于配置和源文件的哈希缓存 Nuxt 构建产物。

这仅适用于 `srcDir` 和 `serverDir` 中的源文件，用于您应用的 Vue/Nitro 部分。

此标志默认禁用，但您可以启用它：

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

启用后，以下文件的更改将触发完全重建：

```bash [目录结构]
.nuxtrc
.npmrc
package.json
package-lock.json
yarn.lock
pnpm-lock.yaml
tsconfig.json
bun.lock
bun.lockb
```

此外，`srcDir` 中任何文件的更改都将触发 Vue 客户端/服务端包的重建。Nitro 将始终被重建（不过正在进行相关工作，以允许 Nitro 声明其可缓存的产物及其哈希）。

<note>

最多保留 10 个缓存压缩包。

</note>
</read-more>
</read-more>

## checkOutdatedBuildInterval

设置检查新构建的时间间隔（以毫秒为单位）。当 `experimental.appManifest` 为 `false` 时此功能被禁用。

设置为 `false` 可禁用该检查。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    checkOutdatedBuildInterval: 3600000, // 1 小时，或 false 表示禁用
  },
})
```

## extraPageMetaExtractionKeys

`definePageMeta()` 宏是收集页面构建时元数据的有用方式。Nuxt 本身提供了一组受支持的键列表，用于驱动一些内部功能，例如重定向、页面别名和自定义路径。

此选项允许在使用 `scanPageMeta` 时传入额外的键以从页面元数据中提取。

```vue
<script lang="ts" setup>
definePageMeta({
  foo: 'bar',
})
</script>
```

```ts
export default defineNuxtConfig({
  experimental: {
    extraPageMetaExtractionKeys: ['foo'],
  },
  hooks: {
    'pages:resolved' (ctx) {
      // ✅ 现在可以访问 foo
    },
  },
})
```

这样模块就可以在构建上下文中从页面元数据访问额外的元数据。如果你在模块中使用此功能，建议同时[使用你的键扩展 `NuxtPage` 类型](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/pages#typing-custom-metadata)。

## extractSerializablePageMeta

当 `future.compatibilityVersion` 为 `5` 或更高版本时，默认启用。

默认情况下，Nuxt 只会在构建时读取 `definePageMeta()` 的固定键列表（以及 `extraPageMetaExtractionKeys` 中的任何内容）；其他所有内容都会在运行时从每个页面单独生成的模块中解析。启用此选项后，Nuxt 会直接将每个可序列化为 JSON 的属性写入生成的路由记录中。

当页面的 `definePageMeta()` 的所有属性都可以静态解析时，路由将完全不再导入该页面的 meta 模块，从而使开发模块图中每个页面减少一个模块。

```vue
<script lang="ts" setup>
definePageMeta({
  layout: { name: 'admin', props: { collapsed: true } },
  title: 'Dashboard',
})
</script>
```

值无法序列化的属性（函数、变量引用、展开运算符、计算属性键）不受影响，仍会在运行时解析。

当 [`scanPageMeta`](#scanpagemeta) 为 `false` 时，此选项不会产生任何影响，因为此时路由记录不会覆盖 meta 模块。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    extractSerializablePageMeta: false,
  },
})
```

## navigationRepaint

在导航之前等待一个动画帧，让浏览器有机会在响应用户交互时重新绘制。

在导航到预渲染路由时，这可以降低 INP。

此标志默认启用，但你可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    navigationRepaint: false,
  },
})
```

## navigateToEarlyReturn

将 `<script setup>` 中顶层的 `await navigateTo()` 调用转换为：当导航成功时，从编译后的 `setup()` 函数提前返回。

如果不启用此标志，`await navigateTo()` 之后的代码仍会继续运行，这可能导致后续代码（包括后续的 `navigateTo` 调用）覆盖重定向，或尝试渲染缺少数据的页面。启用此标志后，成功的导航会停止执行其余的 setup 代码，并且组件会在导航进行期间渲染一个占位注释。

此标志在 `compatibilityVersion: 5` 时默认启用，但您可以禁用它：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    navigateToEarlyReturn: false,
  },
})
```

```vue [pages/example.vue]
<script setup lang="ts">
const { data } = await useFetch('/api/data')

if (!data.value) {
  await navigateTo('/fallback')
}

// 启用此标志后，仅当未发生导航时才会运行这里
const processed = data.value!.map(item => item.name)
</script>
```

此转换仅适用于 `<script setup>` 中顶层的 `await navigateTo()` 语句，且其结果未被使用。带有 `open` 选项的调用（或无法进行静态分析的选项）不会被转换，因为它们不应阻止当前页面渲染。

仅当导航成功时才会提前返回（也就是说，当 `navigateTo` 解析为 `undefined` 时）。如果导航被中止或失败（例如被导航守卫阻止，或导航到当前路由），其余 setup 代码会继续运行。导航成功后，`navigateTo` 调用之后的任何代码都不会运行：这包括 `defineExpose` 以及 `<script setup>` 中后续注册的任何生命周期钩子。

<read-more to="https://github.com/nuxt/nuxt/issues/23698" icon="i-simple-icons-github" target="_blank">

在 GitHub issue 中查看完整说明。

</read-more>

## normalizeComponentNames

Nuxt 会更新自动生成的 Vue 组件名称，以匹配用于自动导入组件时的完整组件名。

如果遇到问题，您可以禁用此功能。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    normalizeComponentNames: false,
  },
})
```

默认情况下，如果您没有手动设置，Vue 会为组件分配与组件文件名匹配的名称。

```bash [目录结构]
├─ components/
├─── SomeFolder/
├───── MyComponent.vue
```

在这种情况下，Vue 认为组件名是 `MyComponent`。如果您想对它使用 `<KeepAlive>`，或在 Vue DevTools 中识别它，您需要使用该组件名。

但为了自动导入它，您需要使用 `SomeFolderMyComponent`。

通过设置 `experimental.normalizeComponentNames`，这两个值将匹配，Vue 将生成与 Nuxt 组件命名模式一致的组件名称。

## normalizePageNames

确保页面组件名称与其路由名称匹配。此功能会在页面组件上设置 `__name` 属性，使 Vue 的 `<KeepAlive>` 能通过名称正确识别它们。

默认情况下，Vue 根据文件名分配组件名称。例如，`pages/foo/index.vue` 和 `pages/bar/index.vue` 都会被命名为 `index`。这种情况让基于名称的 `<KeepAlive>` 过滤变得不可靠，因为多个页面共享相同的名称。

开启 `normalizePageNames` 后，页面组件将以路由名称命名（例如 `foo` 和 `bar`），这样您就可以使用 `<KeepAlive>` 的 `include`/`exclude` 功能，而不用为每个页面手动添加 `defineOptions({ name: '...' })`。

当 `future.compatibilityVersion` 设置为 `5` 或更高时，此标志默认启用，但您可以禁用该功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    normalizePageNames: false,
  },
})
```

```vue [app.vue]
<template>
  <NuxtPage :keepalive="{ include: ['foo'] }" />
</template>
```

## spaLoadingTemplateLocation

在渲染仅客户端页面（`ssr: false`）时，可选地渲染一个加载屏幕（来自 `~/spa-loading-template.html`）。

可以将其设置为 `within`，将按如下方式渲染：

```html
<div id="__nuxt">
  <!-- SPA 加载模板 -->
</div>
```

或者，您可以通过将其设置为 `body` 将模板与 Nuxt 应用根并列渲染：

```html
<div id="__nuxt"></div>
<!-- SPA 加载模板 -->
```

这可以避免在为仅客户端页面执行水合时出现白屏闪烁。

## browserDevtoolsTiming

为浏览器开发者工具启用 Nuxt 钩子的性能标记。这会在基于 Chromium 的浏览器的 Performance 选项卡中添加可跟踪的性能标记，便于调试和优化性能。

在开发模式下默认启用此功能。如果需要禁用，可以这样做：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    browserDevtoolsTiming: false,
  },
})
```

<read-more to="https://github.com/nuxt/nuxt/pull/29922" icon="i-simple-icons-github" target="_blank" color="gray">

查看 PR #29922 以获取实现细节。

</read-more>

<read-more to="https://developer.chrome.com/docs/devtools/performance/extension#tracks" icon="i-simple-icons-googlechrome" target="_blank" color="gray">

了解有关 Chrome DevTools Performance API 的更多信息。

</read-more>

## debugModuleMutation

记录模块上下文中对 `nuxt.options` 的变更，以帮助调试 Nuxt 初始化阶段模块所做的配置更改。

当启用 `debug` 模式时默认启用此功能。如果需要禁用，也可以这样做：

要显式启用它：

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

<read-more to="https://github.com/nuxt/nuxt/pull/30555" icon="i-simple-icons-github" target="_blank" color="gray">

查看 PR #30555 以获取实现细节。
:::

## 延迟水合

为 `<Lazy>` 组件启用延迟水合（hydration）策略，通过延迟组件的水合来提高性能。

默认启用延迟水合，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    lazyHydration: false,
  },
})
```

<read-more to="https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/components#delayed-or-lazy-hydration" icon="i-simple-icons-github" color="gray">

阅读更多有关延迟水合的信息。

</read-more>

## templateImportResolution

禁用从添加模板的模块的路径解析 Nuxt 模板中的导入。

默认情况下，Nuxt 会尝试将模板中的导入相对于添加它们的模块进行解析。将此设置为 `false` 会禁用该行为，这在某些环境中遇到解析冲突时可能有用。

此标志默认启用，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    templateImportResolution: false,
  },
})
```

<read-more to="https://github.com/nuxt/nuxt/pull/31175" icon="i-simple-icons-github" target="_blank" color="gray">

查看 PR #31175 以获取实现细节。

</read-more>

## templateRouteInjection

默认情况下，自动导入的 `useRoute()` composable 返回的路由对象会与 `<NuxtPage>` 中当前可见页面保持同步。`vue-router` 导出的 `useRoute` 或 Vue 模板中可用的默认 `$route` 对象则不然。

启用此选项将注入一个混入，以使模板中的 `$route` 对象与 Nuxt 管理的 `useRoute()` 保持同步。

此标志默认启用，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    templateRouteInjection: false,
  },
})
```

## 装饰器

此选项可在整个 Nuxt/Nitro 应用中启用装饰器语法。

当使用 Vite 构建器（默认）时，装饰器会通过 [Babel](https://babeljs.io/) 降级（lowered）为使用 [`@babel/plugin-proposal-decorators`](https://babeljs.io/docs/babel-plugin-proposal-decorators)。当使用 webpack 或 rspack 构建器时，装饰器会通过 [esbuild](https://github.com/evanw/esbuild/releases/tag/v0.21.3) 降级。

长期以来，TypeScript 通过 `compilerOptions.experimentalDecorators` 支持装饰器。该实现早于 TC39 标准化过程。现在，装饰器已成为一个[第 3 阶段提案](https://github.com/tc39/proposal-decorators)，并在 TS 5.0+ 中无需特殊配置即可支持（参见 [https://github.com/microsoft/TypeScript/pull/52582](https://github.com/microsoft/TypeScript/pull/52582) 和 [https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators）。](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators%EF%BC%89%E3%80%82)

启用 `experimental.decorators` 是启用对 TC39 提案的支持，**不是** 启用 TypeScript 之前的 `compilerOptions.experimentalDecorators` 实现。

<warning>

请注意，在最终成为 JS 标准之前，可能还会发生更改。

</warning>

### 用法示例

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

当使用 Vite 构建器或 Nitro 服务器构建时，您需要安装额外的 Babel 包作为开发依赖：

<code-group>

```bash [npm]
npm install -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
```

```bash [pnpm]
pnpm add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
```

```bash [yarn]
yarn add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
```

</code-group>

<tip>

如果这些包尚未安装，Nuxt 会自动提示您进行安装。

</tip>

```ts [app/app.vue]
function something (_method: () => unknown) {
  return () => 'decorated'
}

class SomeClass {
  @something
  public someMethod () {
    return 'initial'
  }
}

const value = new SomeClass().someMethod()
// 这里将返回 'decorated'
```

## 默认值

此项允许为 Nuxt 核心组件和组合式函数指定默认选项。

未来这些选项可能会被移至其他位置，例如 `app.config` 或 `app/` 目录。

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    defaults: {
      nuxtLink: {
        componentName: 'NuxtLink',
        prefetch: true,
        prefetchOn: {
          visibility: true,
        },
      },
      useAsyncData: {
        deep: true,
      },
      useState: {
        resetOnClear: true,
      },
    },
  },
})
```

`useState.resetOnClear` 选项控制 [`clearNuxtState`](https://nuxt.zhcndoc.com/docs/4.x/api/utils/clear-nuxt-state) 是否将状态重置为其初始值（由 [`useState`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-state) 的 `init` 函数提供），而不是将其设为 `undefined`。在 `compatibilityVersion: 5` 时，此选项默认为 `true`。

## purgeCachedData

是否在路由导航时清理 Nuxt 的静态和 asyncData 缓存。

Nuxt 将自动清除 `useAsyncData` 和 `nuxtApp.static.data` 的缓存数据。这有助于防止内存泄漏并确保在需要时加载最新数据，但您也可以禁用此功能。

此标志默认启用，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    purgeCachedData: false,
  },
})
```

<read-more to="https://github.com/nuxt/nuxt/pull/31379" icon="i-simple-icons-github" target="_blank" color="gray">

查看 PR #31379 以获取实现细节。

</read-more>

## prefetchPreloadTags

当 `<NuxtLink>` 被预取且目标路由启用了 [payload extraction](#payloadextraction)（预渲染和缓存路由的默认设置）时，会将目标通过 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head)（或通过 [`@nuxt/image`](https://image.nuxt.com) 的 `<NuxtImg preload>` 等模块）设置的任何 `<link rel="preload">` 提示转发到当前文档中。

转发的链接会从 `rel="preload"` 降级为 `rel="prefetch"`，但 `as="image"` 提示除外，它们会保留 `rel="preload"`，并去除任何 `fetchpriority`。

只会转发用户定义的 head 标签；构建时的 JS/CSS chunk preload 已由预取流水线单独处理。

此标志默认关闭，因为结合 `prefetchOn: 'visibility'`（`<NuxtLink>` 的默认值）时，可能会一次触发大量跨路由预取。请在您确认这些目标预加载值得为用户通常会遇到的链接转发之后再启用它。

Chromium 和 Safari 会针对用户从未访问的路由上每个被转发的图片提示记录 `was preloaded using link preload but not used within a few seconds` 警告。转发的图片请求也不会携带 `Purpose: prefetch` 标头，因此会作为普通流量计入图片 CDN 配额、速率限制和分析数据。

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

<read-more to="https://github.com/nuxt/nuxt/issues/34953" icon="i-simple-icons-github" target="_blank" color="gray">

查看问题单 #34953，了解设计动机。

</read-more>

## prefetchPreloadTags

当 `<NuxtLink>` 被预取且目标路由启用了 [payload extraction](#payloadextraction)（预渲染和缓存路由的默认设置）时，会将目标通过 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head)（或通过 [`@nuxt/image`](https://image.nuxt.com) 的 `<NuxtImg preload>` 等模块）设置的任何 `<link rel="preload">` 提示转发到当前文档中。

转发的链接会从 `rel="preload"` 降级为 `rel="prefetch"`，以免与当前页面的关键资源竞争。只有用户定义的 head 标签会被转发；构建时的 JS/CSS chunk preload 已由预取流水线单独处理。

此标志默认关闭，因为结合 `prefetchOn: 'visibility'`（`<NuxtLink>` 的默认值）时，可能会一次触发大量跨路由预取。请在您确认这些目标预加载值得为用户通常会遇到的链接转发之后再启用它。

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

<read-more to="https://github.com/nuxt/nuxt/issues/34953" icon="i-simple-icons-github" target="_blank" color="gray">

查看 issue #34953 了解设计动机。

</read-more>

## prefetchPreloadTags

当 `<NuxtLink>` 被预取，并且目标路由启用了 [payload extraction](#payloadextraction)（这是预渲染和已缓存路由的默认行为）时，会将目标通过 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head)（或通过诸如 [`@nuxt/image`](https://image.nuxt.com) 的 `<NuxtImg preload>` 之类的模块）设置的任何 `<link rel="preload">` 提示转发到当前文档中。

这些被转发的链接会从 `rel="preload"` 降级为 `rel="prefetch"`，这样它们就不会与当前页面的关键资源竞争。只有用户自定义的 head 标签会被转发；构建时的 JS/CSS 代码块预加载已经由预取管线单独处理。

此标志默认关闭，因为它与 `prefetchOn: 'visibility'`（`<NuxtLink>` 的默认值）结合时，可能会一次性触发大量跨路由预取。等你确认目标预加载值得为用户通常会遇到的链接进行转发后，再启用它。

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

<read-more to="https://github.com/nuxt/nuxt/issues/34953" icon="i-simple-icons-github" target="_blank" color="gray">

有关动机，请参见 issue #34953。

</read-more>

## granularCachedData

在刷新 `useAsyncData` 和 `useFetch` 的数据时（无论是由 `watch`、`refreshNuxtData()` 还是手动调用 `refresh()` 触发），是否调用并使用 `getCachedData` 的结果。

此标志默认启用，但您可以禁用此功能：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    granularCachedData: false,
  },
})
```

<read-more to="https://github.com/nuxt/nuxt/pull/31373" icon="i-simple-icons-github" target="_blank" color="gray">

查看 PR #31373 以获取实现细节。

</read-more>

## stripNeverHydratedData

默认情况下，对在使用 `hydrate-never` 延迟水合的组件中发出的 `useAsyncData` 和 `useFetch` 调用应用 [`serialize: false`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-async-data#params)，将它们的数据排除在 `__NUXT_DATA__` 负载之外。由于这些组件永远不会在客户端进行水合，因此水合不需要它们的数据。

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

显式的 `serialize` 选项始终具有更高优先级。如果同一个键同时被会进行水合的组件共享，请确保各次调用中的 `serialize` 选项保持一致（Nuxt 会在开发环境中针对不匹配情况发出警告）。

## headNext

使用 head 优化：

- 添加 capo.js head 插件，以更高效地在 head 中渲染标签。
- 使用 hash hydration 插件来减少初始 hydration。

此标志默认启用，但你可以将其禁用：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    headNext: false,
  },
})
```

## routeTypedFetch

根据服务器构建器报告的路由为 `$fetch` 和 `useFetch` 提供类型，而不是根据 nitro 通过其 `InternalApi` 接口贡献给 `ServerRoutes` 的响应提供类型。

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

生成的路由集会附带处理程序验证的 `body`、`query` 和 `headers`，以及其响应（按其在线路上传输时的形式进行类型标注），因此解析成功的调用比以前具有更严格的类型：

- 处理程序返回的 `Date` 在调用处的类型为 `string`
- 处理程序验证的 `body` 不能省略，也不能提供错误的结构
- 路由不响应的方法会被拒绝
- 不再接受 `params`，因为它以前只是 `query` 的别名
- 如果你通过手动扩展 `ServerRoutes` 注册了路由，就需要重写它，因为对路由的两种描述有所不同（参见[升级指南](https://nuxt.com/docs/5.x/getting-started/upgrade#typed-fetch-rebuilt-on-generated-route-types)）。
在重写后的形状中使用 `Endpoint`（从 `nuxt/app` 导入）声明的路由，无论 `routeTypedFetch` 开启还是关闭，类型都相同，因此你可以在切换之前重写它

由于上述变化，此功能默认不启用，而 `future.compatibilityVersion: 5` 会启用它。显式设置此选项可以选择类型方式，而不受兼容性版本影响，因此你可以在迁移到 Nuxt 5 之前采用它，也可以迁移到 Nuxt 5 时设置 `routeTypedFetch: false`，然后单独采用它。

<note>

仅在两种类型声明都受支持期间，此选项才会存在。从 Nuxt 5 开始，生成的路由集将是唯一的数据来源，此选项也会被移除。

</note>

<note>

Nuxt 4 运行于 nitro v2 上，而 nitro 会声明一个使用 `InternalApi` 提供类型的全局 `$fetch`。在需要让生成的路由类型应用于直接调用的地方，从 `#build/fetch` 导入 `$fetch`；`useFetch`、`useLazyFetch` 和 `useRequestFetch()` 不受影响。

</note>

## strictRouteTypes

拒绝对没有服务器路由响应的路径发起请求。需要启用
[`routeTypedFetch`](#routetypedfetch)，它会根据服务器将要提供的路由为 `$fetch` 和 `useFetch` 提供类型。

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

启用 `routeTypedFetch` 后，无论此选项设置为何值，响应类型都会由响应请求的处理程序决定。此选项决定的是 Nuxt 无法识别的路径属于错误，还是只会被标记为 `unknown`。

- `false`（默认值）- Nuxt 无法识别的路径会被接受，且解析结果为 `unknown`，不会拒绝任何方法。Nuxt 无法知晓请求可能得到响应的所有方式：nitro 中间件、[`routeRules`](https://nuxt.zhcndoc.com/docs/4.x/guide/concepts/rendering#hybrid-rendering) 代理或兜底处理程序，都可以响应未由路由描述的路径。
- `true` - 仅接受服务器构建器报告的路由，以及这些路由支持的方法。
- `'isomorphic'` - 与 `true` 一样，同时将页面作为返回 `string` 的 `GET` 路由包含在内，因此 `$fetch('/about')` 的类型会由 Vue router 提供的路由决定，而不是被拒绝。

启用此选项后，拼写错误和路由不支持的方法都会报错：

```ts
// server/api/todos.post.ts answers POST only
await $fetch('/api/todos', { method: 'POST' })
await $fetch('/api/todo', { method: 'POST' })
//           ^ no POST route matches '/api/todo'
await $fetch('/api/todos')
//           ^ no GET route matches '/api/todos'
```

有两种情况仍会被接受，因为它们不由 Nuxt 描述：绝对 URL（`$fetch('https://example.com')`），以及运行时构建的路径；后者会解析为 `unknown`，与关闭此选项时一样。`baseURL` 会在匹配之前解析到路径中，因此通过它发出的请求会根据其实际请求的路由进行检查。显式指定响应类型也会使调用退出类型推断，因为这样会关闭对请求的推断：

```ts
const data = await $fetch<{ id: string }>(`/api/${resource}`)
```

<note>

`public/` 目录中的文件不是服务器构建器报告的路由，因此启用 `strictRouteTypes` 后，请求这些文件会报错。请为这些请求显式指定响应类型，或关闭此选项。

</note>

仅在路由可以枚举的地方启用此选项。带有兜底页面的应用在 `'isomorphic'` 模式下会匹配所有路径，这虽然是正确的，但也意味着此选项不会对路径施加任何限制。

## pendingWhenIdle

`pendingWhenIdle` 控制 `useAsyncData` 和 `useFetch` 返回的 `pending` ref。

当 `pendingWhenIdle` 为 `false`（默认值）时，`pending` 在请求进行中为 `true`，并且与 `status === 'pending'` 一致。当 `status` 为 `idle` 时，`pending` 始终保持 `false`。你可以在 `{ immediate: false }` 的情况下看到这一点，或者在服务端渲染期间使用 `{ server: false }` 时看到这一点。

设置 `pendingWhenIdle: true`，这样当 `status` 为 `idle` 且没有可用的缓存数据时，`pending` 也会为 `true`。当你的加载 UI 需要区分 `idle` 和正在进行中的请求时，请使用 `status`。

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

## entryImportMap

默认情况下，Nuxt 会通过使用导入映射（import map）解析 bundle 的入口 chunk，从而提高 chunk 的稳定性。

这会在 `<head>` 标签顶部注入一个导入映射：

```html
<script type="importmap">{"imports":{"#entry":"/_nuxt/DC5HVSK5.js"}}</script>
```

在 Vite 发出的脚本 chunk 中，导入将来自 `#entry`。这意味着入口的更改不会使那些未改变的 chunk 失效。

<note>

如果您已将 `vite.build.target` 配置为包含不支持 import map 的浏览器，或者已将 `vite.build.rolldownOptions.output.entryFileNames` 配置为不包含 `[hash]` 的值，Nuxt 会智能地禁用此功能。

</note>

如果需要禁用该功能，您可以这样做：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    entryImportMap: false,
  },
  // 或者，更好地告诉 Vite 您的目标环境
  // Nuxt 将遵循此配置
  vite: {
    build: {
      target: 'safari13',
    },
  },
})
```

## typescriptPlugin

启用 `@dxup/nuxt` 模块的增强 TypeScript 开发体验。

这个实验性插件为在 Nuxt 应用中使用 TypeScript 提供了更好的集成和开发工具，以改善开发体验。

此标志默认情况下是禁用的，但您可以启用此功能：

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

<important>

要使用此功能，您需要：

- 将 `typescript` 安装为依赖项
- 配置 VS Code 以使用您的工作区 TypeScript 版本（请参阅 [VS Code 文档](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-the-workspace-version-of-typescript)）

</important>

<read-more to="https://github.com/KazariEX/dxup" icon="i-simple-icons-github" target="_blank">

详细了解 **@dxup/nuxt**。

</read-more>

## viteEnvironmentApi

启用 Vite 6 的新 [Environment API](https://vite.dev/guide/api-environment)，以改进构建配置和插件架构。

当你将 `future.compatibilityVersion` 设置为 `5` 时，此功能默认启用。你也可以显式启用它进行测试：

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

Vite Environment API 可提高开发构建与生产构建之间的一致性，提供更精细的环境专属配置控制，并提升性能。

<important>

启用此功能会改变 Vite 插件的注册和配置方式。有关如何更新插件的详细信息，请参阅 [Vite Environment API 迁移指南](https://nuxt.com/docs/5.x/getting-started/upgrade#migration-to-vite-environment-api)。

</important>

<read-more to="https://vite.dev/guide/api-environment" target="_blank">

详细了解 Vite 的 Environment API。

</read-more>

## ssrStreaming

启用 SSR 流式传输，以显著提升首字节时间（TTFB）。启用后，服务器会立即发送 HTML 外壳（包括 `<head>`、样式、预加载提示和入口脚本），然后使用 Vue 的 `renderToWebStream` 逐步流式输出渲染后的 body 内容。

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

对于 bot 和爬虫用户代理（例如 Googlebot、Bingbot 等），流式传输会自动禁用，以确保搜索引擎接收到完整渲染的 HTML，保证 SEO 安全。默认模式只匹配索引爬虫；Lighthouse 和其他审计工具会刻意排除在外，因此合成测量反映的是用户实际获得的同样流式响应。

你可以使用 `botRegex` 自定义选择退出流式传输的用户代理。`user-agent` 标头与此模式匹配的请求**不会**进行流式传输：它会收到完整渲染的缓冲式 HTML。不匹配的请求则会进行流式传输。设置 `botRegex` 会替换默认模式，而不是在其基础上添加，因此请列出你希望排除在流式传输之外的所有爬虫：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: {
      botRegex: /googlebot|bingbot|my-internal-crawler/i,
    },
  },
})
```

您也可以通过 `routeRules` 按路由控制流式传输：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: true,
  },
  routeRules: {
    '/no-stream/**': { streaming: false },
  },
})
```

<warning>

**自动回退到非流式渲染。** 流式传输会在外壳被刷新时立即提交响应状态和头信息，因此与那些需要在渲染后修改响应的功能不兼容。匹配以下任一条件的请求不会采用流式传输；它们会使用缓冲式渲染器，或直接短路为重定向/错误响应：

- 路由的 `routeRules` 设置了 `noScripts`、`cache`、`isr`、`swr`、`redirect` 或 `streaming: false`
- `ssr: false` 路由（已经采用 SPA 渲染）
- Bot/爬虫用户代理，即 `user-agent` 与 `botRegex` 匹配的请求
- 预渲染路由（`nuxt generate`）
- 来自插件、中间件或页面 setup 的服务端 `navigateTo()` 重定向
- 初始渲染期间抛出的致命错误（在外壳刷新之前）

</warning>

<warning>

**响应状态和头信息必须在外壳刷新之前设置。** 流式传输会随着第一个字节提交 HTTP 状态和头信息，因此之后对响应所做的任何修改都无法到达客户端。这是流式传输的固有特性，不是 Nuxt 特有的 bug。

边界就是外壳刷新的时刻：

- **会到达客户端**：来自 Nuxt 和 Nitro 插件的修改，这些插件会在渲染开始前运行完毕。
- **会被丢弃**：在组件渲染期间进行的 `setResponseStatus()`、`useResponseHeader()`、`useCookie()` 写入以及 h3 的 `setHeader()`/`appendResponseHeader()` 调用（包括在路由中间件或 `<script setup>` 中 `await` 之后的调用），因为这些工作发生在外壳已经发送到网络之后。

要保留响应修改，请将其移入插件，或让该路由退出流式传输：

- `routeRules: { '/path': { streaming: false } }`：静态、按路由配置。
- 带有 `ctx.prefersStream = false` 的 `render:route` 钩子：运行时、按请求控制（例如针对会条件性设置 404 的路由）。

在开发环境中，流式处理器会记录一个警告，指出被丢弃的修改和对应路由，因此这些问题不会静默失败。

</warning>

<note>

如果在流式传输过程中、HTTP 状态已提交之后发生错误，则会设置 `payload.error`，并且仍会输出闭合标签，形成一个结构完整的文档，这样客户端就能在 hydration 期间接收到错误并渲染错误页。在外壳刷新之前抛出的错误会进入缓冲式错误渲染器，并带有正确的状态码。

</note>

<note>

**路由样式会流式传输，JS 提示仅针对入口。** 外壳会在路由渲染之前刷新，因此其 `<head>` 只包含入口 chunk 的样式和提示。一旦渲染注册了页面和布局模块，它们的 CSS 就会紧跟在外壳之后流式输出（在启用 `inlineStyles` 时以内联 `<style>` 形式输出，否则以样式表链接形式输出），因此页面、布局以及顶层异步组件的样式会在 body 绘制前到达（嵌套异步组件存在 FOUC 注意事项，见下文）。特定路由的 JS chunk 不会从外壳中预加载；浏览器会在解析入口脚本后发现它们。流式传输会为每条路由提升 TTFB；对于 JS 与入口 chunk 重叠较多的路由，LCP 收益最大。

</note>

<warning>

**外壳刷新后注册的 head 标签会变成客户端补丁。** 渲染器会等待第一轮渲染结束后再刷新外壳，因此在 `<script setup>` 中同步调用的 `useHead`/`useSeoMeta`（位于任何 `await` 之前）、插件或中间件中注册的标签，都会像往常一样渲染到外壳的 `<head>` 中。较晚注册的标签（在 setup 中 `await` 之后，或在嵌套 `<Suspense>` 边界内注册）无法写入已发送的 `<head>`；它们会以内联脚本的形式传递，并在客户端修补 DOM。

运行 JavaScript 的客户端会应用此补丁，而与 `botRegex` 匹配的客户端根本不会进行流式传输，因此会收到完整缓冲的 `<head>`。其他客户端（未列入 `botRegex` 的爬虫、链接预览工具、`curl`）都不会看到这些标签。JSON-LD 脚本、`noscript` 标签和定位在 body 中的标签是例外：它们会在 `</body>` 之前作为实际标记渲染，因此所有客户端都能读取。其他对 SEO 至关重要的标签（规范链接、社交媒体元数据）应同步注册，或者通过 `routeRules: { '/path': { streaming: false } }` 让该路由退出流式传输。

</warning>

<note>

**组件岛与流式传输兼容。** 岛内插槽内容和选择性客户端（`nuxt-client`）组件通常会在渲染后阶段被拼接进 HTML，但一旦 body 已经流经岛锚点，这就不可能了。为此，渲染器会将每个岛的 teleport 以无副作用的 `<template>` 形式输出到文档末尾，并使用一个在 hydration 之前运行的内联脚本将其移动到位。对应用代码而言这是透明的。例外是使用 `features.noScripts` 构建且包含岛组件的应用，因为此时 relocation 脚本无法运行，所以会回退到缓冲式渲染器。

</note>

### 模块钩子

模块通过现有的 `render:html` 钩子参与流式响应（现在第二个参数上带有 `streaming: true` 标志），并额外提供一个按请求决策钩子和两个仅用于流式传输的钩子：

- **render:route** 会在每次渲染开始前、每个请求触发一次（无论是否启用流式传输）。读取 `ctx.canStream` 可查看该路由是否可流式传输，并设置 `ctx.prefersStream = false` 以强制本次请求使用缓冲式渲染，例如基于 cookie、认证状态或 A/B 分桶。渲染器仅在 `canStream && prefersStream` 为真时才会流式传输。这是静态 `routeRules` / `botRegex` 配置的运行时逃生口。
- **render:html** 会在外壳刷新之前触发一次，其第二个参数上带有 `streaming: true`。对 `htmlAttrs`、`head`、`bodyAttrs` 和 `bodyPrepend` 的修改会真正发送到网络。对 `body`/`bodyAppend` 的修改会被丢弃，因为 body 即将开始流式输出（开发模式下会发出警告）。仅修改 head 字段的模块（CSP 注入、OG 标签、分析元数据）无需改动代码即可在流式传输中正常工作。
- **render:html:chunk** 会在渲染器生成每个 chunk、并将其入队之前触发。修改 `ctx.chunk: Uint8Array` 可转换字节流（例如注入 nonce）；读取 `ctx.index` 可区分第一个 chunk 与后续 chunk。
- **render:html:close** 会在 body 流完成后、闭合标签之前触发。修改 `ctx.bodyAppend: string[]` 可注入最终标记（body 末尾的分析标签、服务端渲染的调试组件等）。

```ts
// modules/streaming-csp/src/runtime/server-plugin.ts
import { defineNitroPlugin } from '#imports'

export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('render:html', (ctx, { event }) => {
    const nonce = event.context.cspNonce
    if (!nonce) { return }
    // 对流式（pre-shell）和缓冲式（post-render）路径都有效。
    for (let i = 0; i < ctx.head.length; i++) {
      ctx.head[i] = ctx.head[i].replace(/<script(?![^>]*\snonce=)/g, `<script nonce="${nonce}"`)
    }
  })
})
```

<note>

**CSP nonce。** 流式渲染器会输出若干绕过 unhead 的内联脚本和样式：bootstrap 队列、IIFE、suspense head 推送、岛 teleport 重定位以及路由 `<style>` 块。如果渲染后的 head 脚本上存在 `nonce`，渲染器会自动在所有这些内容上复用它，因此严格的 `script-src`/`style-src 'nonce-…'` 策略不会阻止流式传输。模块只需把 nonce 放到 head 脚本上（如上所示）；`render:html:chunk` 钩子仍可用于为组件渲染到 body 中的脚本打标。

</note>

<warning>

**SFC 样式在开发模式下的 FOUC：** 在开发环境中，Vite 会将 SFC `<style>` 块作为 JavaScript 模块提供，并在模块执行后由客户端注入样式，而不是在外壳中输出对应的 `<link>`。使用流式传输时，浏览器会在这些样式注入模块运行之前开始绘制流式 DOM，因此 SFC 定义的样式会短暂以未应用样式的形式闪烁。

解决方法：将影响首屏绘制的关键样式放入通过 `css: ['~/assets/main.css']` 注册的全局 CSS 文件中。全局 CSS 文件会作为 `<link rel="stylesheet">` 输出到外壳的 `<head>` 中，并在 body 内容流式输出之前生效。SFC `<style>` 块仍然适合用于不影响初始绘制的组件作用域样式。

生产构建会将所有样式提取为真实的 CSS 文件（或通过 `features.inlineStyles` 内联），因此这只影响 `nuxt dev`。请使用 `nuxt build && nuxt preview` 验证流式渲染效果。

</warning>

<warning>

**嵌套异步组件在生产环境中的 FOUC：** 渲染器会将路由 CSS 内联到紧跟外壳之后发送的一个 chunk 中。它只能内联在那一刻已经注册的组件样式：页面、布局，以及直接放在 `<Suspense>` 边界内的任何异步组件（Vue 会在渲染开始时主动实例化这些组件）。

一个被渲染在*另一个异步组件内部*的异步组件，只有在其父组件解析完成后才会被实例化，也就是在第一个 chunk 已经流式输出之后。它的 SFC `<style>` 会错过外壳后的样式 chunk，并在最终的 HTML 闭合部分输出，位于该组件自己的 DOM 之后。浏览器会在最后一个 chunk 到达之前将该组件绘制为未应用样式状态。

可通过避免在深层嵌套异步组件中放置影响首屏绘制的样式来规避：

- 将控制初始绘制的样式放入全局 CSS 文件（`css: ['~/assets/main.css']`）；这些样式会进入外壳 `<head>`。
- 使用工具类（Tailwind、UnoCSS）进行样式化：工具类 CSS 位于入口样式表中，而不是按组件的 `<style>` 块中。
- 将拥有影响首屏绘制样式的异步组件直接放在 `<Suspense>` 边界下，而不是嵌套在另一个异步父组件之后。
- 或者通过 `routeRules: { '/path': { streaming: false } }` 让该路由退出流式传输。

对于深层嵌套异步组件中不影响首屏绘制的作用域样式而言，这没有问题：短暂闪烁只会影响首屏以上的内容。

</warning>

## ssrStreaming

启用 SSR 流式传输，可显著提升首字节时间（TTFB）。启用后，服务器会立即发送 HTML 外壳（包括 `<head>`、样式、预加载提示和入口脚本），然后使用 Vue 的 `renderToWebStream` 逐步流式传输渲染后的主体内容。

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

对于 bot 和爬虫用户代理（例如 Googlebot、Bingbot 等），流式传输会自动禁用，以确保搜索引擎接收到完整渲染的 HTML，保证 SEO 安全。默认模式只匹配索引爬虫；Lighthouse 和其他审计工具会刻意排除在外，因此合成测量反映的是用户实际获得的同样流式响应。你可以自定义 bot 检测的正则表达式：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: {
      botRegex: /googlebot|bingbot|my-internal-crawler/i,
    },
  },
})
```

你也可以通过 `routeRules` 按路由控制流式传输：

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: true,
  },
  routeRules: {
    '/no-stream/**': { streaming: false },
  },
})
```

<warning>

**自动回退到非流式渲染。** 流式传输会在外壳刷新后立即提交响应状态和响应头，这与那些需要在渲染后修改响应的功能不兼容。匹配以下任意条件的请求不会进行流式传输；它们会使用缓冲渲染器，或者直接短路为重定向或错误响应：

- 该路由的 `routeRules` 设置了 `noScripts`、`cache`、`isr`、`swr`、`redirect` 或 `streaming: false`
- `ssr: false` 路由（已是 SPA 渲染）
- Bot/爬虫用户代理（由 `botRegex` 控制）
- 预渲染路由（`nuxi generate`）
- 来自插件、中间件或页面 setup 中的服务端 `navigateTo()` 重定向
- 初始渲染期间抛出的致命错误（在外壳刷新之前）

</warning>

<warning>

**响应状态和响应头必须在外壳刷新之前设置。** 流式传输会在发送第一个字节时提交 HTTP 状态和响应头，因此在那之后修改响应的任何内容都无法到达客户端。这是流式传输本身的特性，不是 Nuxt 特有的 bug。

边界就是外壳刷新：

- **会到达客户端**：来自 Nuxt 和 Nitro 插件的修改，它们会在渲染开始前运行完毕。
- **会被丢弃**：在组件渲染期间（包括在路由中间件或 `<script setup>` 中 `await` 之后）进行的 `setResponseStatus()`、`useResponseHeader()`、`useCookie()` 写入，以及 h3 的 `setHeader()`/`appendResponseHeader()` 调用，因为这些工作发生在外壳已经上网之后。

如果想保留某个响应修改，把它移到插件里，或者让该路由退出流式传输：

- `routeRules: { '/path': { streaming: false } }`：静态配置，按路由生效。
- 带有 `ctx.prefersStream = false` 的 `render:route` 钩子：运行时配置，按请求生效（例如某些会条件性设置 404 的路由）。

在开发环境中，流式处理器会记录一条警告，指出被丢弃的修改和对应路由，因此这些问题不会静默失败。

</warning>

<note>

如果在流式传输过程中、HTTP 状态已经提交后发生错误，`payload.error` 会被设置，并且仍会输出闭合标签作为一个格式正确的文档，这样客户端会在 hydration 期间接收到错误并渲染错误页面。在外壳刷新之前抛出的错误会落入带有正确状态码的缓冲错误渲染器。

</note>

<note>

**路由样式会流式传输，JS 提示仅限入口。** 外壳会在路由渲染之前刷新，因此其 `<head>` 只包含入口 chunk 的样式和提示。一旦 render 注册了页面和布局模块，它们的 CSS 会紧接着外壳之后流式传输（在启用 `inlineStyles` 时以内联 `<style>` 形式，否则作为样式表链接），因此页面、布局以及顶层异步组件的样式会在 body 绘制前到达（嵌套异步组件会有 FOUC 注意事项，见下文）。特定路由的 JS chunk 不会从外壳预加载；浏览器会在解析入口脚本后发现它们。流式传输可提升所有路由的 TTFB；对于其 JS 与入口 chunk 重叠的路由，LCP 收益最大。

</note>

<note>

**组件岛与流式传输兼容。** 岛的插槽内容和选择性客户端（`nuxt-client`）组件通常会在渲染后的后处理阶段拼接进 HTML，而一旦 body 已经流过岛锚点，这在流式传输下就不可能了。为此，渲染器会将每个岛的 teleport 作为无害的 `<template>` 放在文档末尾，并通过一个在 hydration 前运行的内联脚本把它们搬回原位。这个过程对应用代码是透明的。例外情况是使用 `features.noScripts` 且包含岛组件的应用，由于无法运行搬运脚本，它们会回退到缓冲渲染器。

</note>

### 模块钩子

模块通过现有的 `render:html` 钩子参与流式响应（现在第二个参数上带有 `streaming: true` 标记），再加上一个按请求决策的钩子和两个仅用于流式传输的钩子：

- **render:route** 在每次请求、渲染开始之前触发，对每次渲染都会执行一次（无论是否启用流式传输）。读取 `ctx.canStream` 可查看该路由是否可以流式传输，并设置 `ctx.prefersStream = false` 来强制该请求使用缓冲渲染，例如基于 cookie、认证状态或 A/B 分流。只有在 `canStream && prefersStream` 时渲染器才会流式传输。这是针对静态 `routeRules` / `botRegex` 配置的运行时逃生通道。
- **render:html** 在外壳刷新之前触发一次，第二个参数上的 `streaming: true` 表示当前为流式模式。对 `htmlAttrs`、`head`、`bodyAttrs` 和 `bodyPrepend` 的修改会到达网络。对 `body`/`bodyAppend` 的修改会被丢弃，因为 body 即将开始流式传输（会在开发模式下发出警告）。只修改 head 字段的模块（CSP 注入、OG 标签、分析元数据）无需改动代码即可在流式传输中正常工作。
- **render:html:chunk** 在渲染器生成每个 chunk 并将其入队之前触发。修改 `ctx.chunk: Uint8Array` 可转换字节流（例如注入 nonce）；读取 `ctx.index` 可区分第一个 chunk 与后续 chunk。
- **render:html:close** 在 body 流结束后、闭合标签之前触发。修改 `ctx.bodyAppend: string[]` 可注入最终标记（body 末尾的分析标签、服务端渲染的调试小部件等）。

```ts
// modules/streaming-csp/src/runtime/server-plugin.ts
import { defineNitroPlugin } from '#imports'

export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('render:html', (ctx, { event }) => {
    const nonce = event.context.cspNonce
    if (!nonce) { return }
    // 对流式（pre-shell）和缓冲（post-render）路径都有效。
    for (let i = 0; i < ctx.head.length; i++) {
      ctx.head[i] = ctx.head[i].replace(/<script(?![^>]*\snonce=)/g, `<script nonce="${nonce}"`)
    }
  })
})
```

<note>

**CSP nonce。** 流式渲染器会输出多个绕过 unhead 的内联脚本和样式：引导队列、IIFE、suspense head 推送、island-teleport 重新定位，以及路由 `<style>` 块。如果渲染后的 head 脚本上存在 `nonce`，渲染器会自动将其复用于所有这些内容，因此严格的 `script-src`/`style-src 'nonce-…'` 策略不会阻止流式传输。模块只需要把 nonce 放到 head 脚本上（如上所示）；`render:html:chunk` 钩子仍可用于为组件渲染到 body 中的脚本加标记。

</note>

<warning>

**SFC 样式在开发模式下会出现 FOUC：** 在开发环境中，Vite 会将 SFC `<style>` 块作为 JavaScript 模块提供，这些模块在执行后才会在客户端注入样式，而外壳中并没有对应的 `<link>`。在流式传输下，浏览器会在这些样式注入模块运行之前就开始绘制流式 DOM，因此 SFC 定义的样式会短暂地以无样式状态闪现。

解决方法：把对首屏绘制至关重要的样式放到通过 `css: ['~/assets/main.css']` 注册的全局 CSS 文件中。全局 CSS 文件会以 `<link rel="stylesheet">` 的形式出现在外壳的 `<head>` 中，并在 body 内容开始流式传输之前生效。对于不影响首屏绘制的组件级样式，SFC `<style>` 块仍然完全可用。

生产构建会把所有样式提取为真正的 CSS 文件（或者通过 `features.inlineStyles` 内联），因此这只会影响 `nuxt dev`。请使用 `nuxt build && nuxt preview` 来验证流式传输下的视觉效果。

</warning>

<warning>

**嵌套异步组件在生产环境下会出现 FOUC：** 渲染器会将路由 CSS 内联到一个在外壳之后立刻发送的 chunk 中。它只能内联当时已经注册的组件的样式：页面、布局，以及直接放在 `<Suspense>` 边界内的任何异步组件（Vue 会在渲染开始时急切实例化这些组件）。

一个在*另一个异步组件内部*渲染的异步组件，只有在其父组件解析完成后才会实例化，也就是第一个 chunk 已经流式传输之后。它的 SFC `<style>` 会错过外壳之后的样式 chunk，而是在闭合 HTML 中输出，位于组件自身 DOM 之后。浏览器会在最终 chunk 到达之前将该组件绘制为无样式状态。

避免这种情况的方法是，不要让深层嵌套的异步组件承担首屏绘制所需的样式：

- 将影响首屏绘制的样式放到全局 CSS 文件中（`css: ['~/assets/main.css']`）；这些样式会到达外壳 `<head>`。
- 使用工具类进行样式设置（Tailwind、UnoCSS）：工具类 CSS 位于入口样式表中，而不是每个组件的 `<style>` 块里。
- 将拥有影响首屏绘制的 `<style>` 的异步组件直接放在 `<Suspense>` 边界下，而不是嵌套在另一个异步父组件后面。
- 或者通过 `routeRules: { '/path': { streaming: false } }` 让该路由退出流式传输。

嵌套异步组件上不影响首屏绘制的作用域样式是没问题的：短暂闪烁只会影响首屏以上内容。

</warning>
</read-more>


## Sitemap

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