实验性功能

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

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

在内部,Nuxt 使用 @nuxt/schema 来定义这些实验性功能。有关更多信息,您可以参考 API 文档源代码

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

alwaysRunFetchOnKeyChange

当 key 改变时是否运行 useFetch,即使它被设置为 immediate: false 且尚未被触发。

如果设置了 immediate: true 或者已经被触发过,当 key 改变时,useFetchuseAsyncData 将始终运行。

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

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

appManifest

使用应用清单(app manifests)在客户端遵守路由规则。

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

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

asyncContext

启用原生的异步上下文,以便 Nuxt 和 Nitro 中的嵌套组合式函数可以访问。这使得在异步组合式函数内部使用组合式函数成为可能,并减少出现 Nuxt instance is unavailable(Nuxt 实例不可用)错误的机会。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    asyncContext: true,
  },
})
请参阅 GitHub PR 上的完整说明。

asyncEntry

启用 Vue bundle 的异步入口点生成,从而辅助模块联邦(module federation)支持。

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

externalVue

在构建时将 vue@vue/*vue-router 外部化(externalize)。

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

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    externalVue: false,
  },
})
此功能可能会在不久的将来被移除。

extractAsyncDataHandlers

useAsyncDatauseLazyAsyncData 调用中的处理函数提取到单独的代码块(chunks)中,以提高代码分割和缓存效率。

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

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

<!-- Before -->
<script setup>
const { data } = await useAsyncData('user', async () => {
  return await $fetch('/api/user')
})
</script>
<!-- After transformation -->
<script setup>
const { data } = await useAsyncData('user', () =>
  import('/generated-chunk.js').then(r => r.default()),
)
</script>

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

此功能仅推荐用于带有负载提取(payload extraction)的静态构建,且数据不需要在运行时重新获取的情况。

emitRouteChunkError

当加载 vite/webpack 代码块(chunks)出错时,触发 app:chunkError 钩子。默认行为是:当导航到新路由且代码块加载失败时,重新加载新路由。

默认情况下,在导航到新路由时,如果代码块加载失败,Nuxt 也会重新加载新路由(automatic)。

设置 automatic-immediate 会导致 Nuxt 在代码块加载失败时立即重新加载当前路由(而不是等待导航)。这对于不由导航触发的代码块错误非常有用,例如当你的 Nuxt 应用加载延迟组件失败时。这种行为的一个潜在缺点是可能会产生不需要的重新加载,例如当你的应用实际上不需要导致错误的代码块时。

你可以通过将此项设置为 false 来禁用自动处理,或者通过将其设置为 manual 来手动处理代码块错误。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    emitRouteChunkError: 'automatic', // or 'automatic-immediate', 'manual' or false
  },
})

enforceModuleCompatibility

如果 Nuxt 模块不兼容,Nuxt 是否应抛出错误(并加载失败)。

此功能默认禁用。

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

restoreState

允许在代码块错误或手动调用 reloadNuxtApp() 后重新加载页面时,从 sessionStorage 恢复 Nuxt 应用状态。

为避免水合(hydration)错误,它仅在 Vue 应用挂载后应用,这意味着初次加载时可能会有闪烁。

在启用此功能之前请仔细考虑,因为它可能会导致意外行为,并且建议为 useState 提供显式键,因为自动生成的键可能在不同的构建之间不匹配。
nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    restoreState: true,
  },
})

inlineRouteRules

使用 defineRouteRules 在页面级别定义路由规则。

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

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

defineRouteRules 工具函数中阅读更多信息。
请在 文档 > 4 X > 指南 > 概念 > 渲染#混合渲染(Hybrid Rendering)中阅读更多信息。

renderJsonPayloads

允许渲染 JSON 负载,并支持恢复(revivifying)复杂类型。

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

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

noVueServer

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

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

parseErrorData

渲染服务端错误页面时是否解析 error.data

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

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

payloadExtraction

控制如何为预渲染和缓存(ISR/SWR)页面交付负载数据。

  • 'client' - 负载内联在初始服务端渲染的 HTML 中,并提取到用于客户端导航的 _payload.json 文件中。
  • true - 无论是初始服务端渲染还是客户端导航,负载都会被提取到单独的 _payload.json 文件中。
  • false - 完全禁用负载提取。负载总是内联在 HTML 中,且不生成任何 _payload.json 文件。

默认值为 true,或者在设置了 compatibilityVersion: 5 时为 'client'。当设置了 ssr: false 时,它会被强制设为 false

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    payloadExtraction: 'client',
  },
})
阅读更多关于负载提取以及各模式影响的内容。

clientNodePlaceholder

在服务端渲染期间,使用注释节点(<!--placeholder-->)而不是 <div> 元素作为仅客户端组件的占位符。

启用后,.client.vue 组件和 createClientOnly() 包装器在服务端渲染一个 HTML 注释,而不是一个空的 <div>。这修复了一个 Vue 水合问题:当占位符 <div> 与实际组件根节点具有相同的标签名时,作用域样式可能不会被应用。

启用此功能意味着传递给 .client.vue 组件的属性(classstyle 等)不会出现在 SSR HTML 中。如果你需要带样式的占位符来防止布局偏移,请改用带有 #fallback 插槽的 <ClientOnly>

future.compatibilityVersion 设置为 5 或更高版本时,此标志会自动启用,但你也可以显式启用它

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

clientFallback

启用实验性的 <NuxtClientFallback> 组件,以便在 SSR 发生错误时在客户端渲染内容。

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

crossOriginPrefetch

使用推测规则 API(Speculation Rules API)启用跨域预获取。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    crossOriginPrefetch: true,
  },
})
阅读更多关于 推测规则 API (Speculation Rules API) 的内容。

viewTransition

启用视图过渡 API(View Transition API)与客户端路由器的集成。

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

你还可以传递一个对象来配置 视图过渡类型(view transition types),这允许根据导航类型使用不同的 CSS 动画

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    viewTransition: {
      enabled: true,
      types: ['slide'],
    },
  },
})
阅读更多关于 视图过渡 API (View Transition API) 的内容。
阅读更多关于 视图过渡 API (View Transition API) 的内容。

writeEarlyHints

在使用 node 服务器时启用早期提示(early hints)的写入。

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

componentIslands

通过 <NuxtIsland>.island.vue 文件启用实验性的组件孤岛(component islands)支持。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    componentIslands: true, // false or 'local+remote'
  },
})
请在 文档 > 4 X > 目录结构 > 应用 > 组件#服务端组件(Server Components)中阅读更多信息。
在非单文件组件(如 <NuxtLink>)上跳过 nuxt-client。请参阅 服务端组件内的客户端组件
你可以在 GitHub 上关注服务端组件的发展路线图。

localLayerAliases

根据层源目录和根目录解析位于各层(layers)中的 ~~~@@@ 别名。

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

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

typedPages

启用新的实验性类型化路由(typed router)。

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

开箱即用,这将启用对 navigateTo<NuxtLink>router.push() 等的类型化支持。

你甚至可以通过使用 const route = useRoute('route-name') 在页面内获取类型化的参数。

watcher

设置用作 Nuxt 监视服务的替代文件监视器(watcher)。

Nuxt 默认使用 chokidar-granular,它会忽略排除在监视之外的顶级目录(如 node_modules.git)。

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

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

设置为 'builder' 以重用活动构建器自己的文件监视器(例如 Vite 的 server.watcher),而不是启动第二个。这减少了在开发模式下活动的文件监视器的数量,并且当 future.compatibilityVersion5 时成为默认设置。如果活动构建器未实现自己的监视器(目前 webpack 和 rspack),Nuxt 会记录一条警告并回退到其默认选择。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    watcher: 'chokidar-granular', // 'chokidar', 'parcel' or 'builder' are also options
  },
})

sharedPrerenderData

Nuxt 会自动在预渲染的页面之间共享负载数据。当预渲染使用 useAsyncDatauseFetch 并在不同页面中获取相同数据的网站时,这可以显著提升性能。

如果需要,你可以禁用此功能。

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

启用此功能时,尤为重要的一点是确保数据的任何唯一键(key)始终能解析到相同的数据。例如,如果你使用 useAsyncData 来获取与特定页面相关的数据,你应该提供一个与该数据唯一匹配的键。(useFetch 应该会自动为你处理这一点。)

// This would be unsafe in a dynamic page (e.g. `[slug].vue`) because the route slug makes a difference
// to the data fetched, but Nuxt can't know that because it's not reflected in the key.
const route = useRoute()
const { data } = await useAsyncData(async (_nuxtApp, { signal }) => {
  return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
})
// Instead, you should use a key that uniquely identifies the data fetched.
const { data } = await useAsyncData(route.params.slug, async (_nuxtApp, { signal }) => {
  return await $fetch(`/api/my-page/${route.params.slug}`, { signal })
})

clientNodeCompat

借助此功能,Nuxt 将使用 unenv 在客户端构建中自动对 Node.js 导入进行 polyfill。

要使诸如 Buffer 之类的全局变量在浏览器中工作,你需要手动注入它们。
import { Buffer } from 'node:buffer'

globalThis.Buffer ||= Buffer

scanPageMeta

Nuxt 在构建时向模块暴露在 definePageMeta 中定义的一些路由元数据(具体为 aliasnamepathredirectpropsmiddleware)。

这仅适用于静态值、字符串或数组,而不适用于变量或条件赋值。有关更多信息和背景,请参阅 原始 issue

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

如果此功能在你的项目中引发问题,你可以将其禁用。

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

cookieStore

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

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

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    cookieStore: false,
  },
})
阅读更多关于 CookieStore 的内容。

buildCache

根据配置和源文件的哈希值缓存 Nuxt 构建产物。

这仅适用于应用中 Vue/Nitro 部分的 srcDirserverDir 内的源文件。

此标志默认禁用,但你可以启用它

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

启用后,对以下文件的更改将触发完整重新构建

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

此外,对 srcDir 内文件的任何更改都将触发 Vue 客户端/服务端 bundle 的重新构建。Nitro 始终会重新构建(尽管目前正在进行相关工作,允许 Nitro 声明其可缓存产物及其哈希值)。

最多保留 10 个缓存 tarball 文件。

checkOutdatedBuildInterval

设置检查新构建的时间间隔(以毫秒为单位)。当 experimental.appManifestfalse 时禁用。

设置为 false 以禁用。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    checkOutdatedBuildInterval: 3600000, // 1 hour, or false to disable
  },
})

extraPageMetaExtractionKeys

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

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

<script lang="ts" setup>
definePageMeta({
  foo: 'bar',
})
</script>
export default defineNuxtConfig({
  experimental: {
    extraPageMetaExtractionKeys: ['foo'],
  },
  hooks: {
    'pages:resolved' (ctx) {
      // ✅ foo is available
    },
  },
})

这允许模块在构建上下文中访问页面元数据中的附加元数据。如果你在模块中使用此功能,建议同时使用你的键扩展 NuxtPage 类型

在导航前等待单个动画帧,这为浏览器提供了重新绘制的机会,以响应用户交互。

它可以在预渲染路由上导航时减少 INP(Interaction to Next Paint)。

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

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

normalizeComponentNames

Nuxt 会更新自动生成的 Vue 组件名称,以匹配你用于自动导入该组件的全组件名。

如果你遇到问题,可以禁用此功能。

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

默认情况下,如果你没有手动设置,Vue 将分配一个与组件文件名匹配的组件名。

目录结构
├─ components/
├─── SomeFolder/
├───── MyComponent.vue

在这种情况下,就 Vue 而言,组件名称将是 MyComponent。如果你想将 <KeepAlive> 与之配合使用,或者在 Vue DevTools 中识别它,你就需要使用这个组件。

但为了自动导入它,你需要使用 SomeFolderMyComponent

通过设置 experimental.normalizeComponentNames,这两个值将匹配,并且 Vue 将生成一个符合 Nuxt 组件命名模式的组件名。

normalizePageNames

确保页面组件名称与其路由名称匹配。这会在页面组件上设置 __name 属性,以便 Vue 的 <KeepAlive> 可以按名称正确识别它们。

默认情况下,Vue 根据文件名分配组件名。例如,pages/foo/index.vuepages/bar/index.vue 的组件名都将是 index。这使得基于名称的 <KeepAlive> 过滤不可靠,因为多个页面共享相同的名称。

启用 normalizePageNames 后,页面组件将以其路由命名(例如 foobar),因此你可以将 <KeepAlive>include/exclude 一起使用,而无需手动向每个页面添加 defineOptions({ name: '...' })

future.compatibilityVersion 设置为 5 或更高版本时,此标志会自动启用,但你可以禁用此功能

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    normalizePageNames: false,
  },
})
app.vue
<template>
  <NuxtPage :keepalive="{ include: ['foo'] }" />
</template>

spaLoadingTemplateLocation

在渲染仅客户端页面(带有 ssr: false)时,我们可以选择性地渲染一个加载屏幕(来自 ~/spa-loading-template.html)。

它可以设置为 within,这将像这样渲染它

<div id="__nuxt">
  <!-- spa loading template -->
</div>

或者,你可以通过将其设置为 body,将模板与 Nuxt 应用根节点并排渲染

<div id="__nuxt"></div>
<!-- spa loading template -->

这避免了在水合仅客户端页面时出现白屏闪烁。

browserDevtoolsTiming

在浏览器开发者工具中为 Nuxt 钩子启用性能标记。这会添加性能标记,你可以在基于 Chromium 的浏览器的“性能 (Performance)”标签页中进行跟踪,这对于调试和优化性能非常有用。

这在开发模式下默认启用。如果你需要禁用此功能,也是可以做到的

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    browserDevtoolsTiming: false,
  },
})
有关实现细节,请参阅 PR #29922。
了解更多关于 Chrome DevTools 性能 API 的信息。

debugModuleMutation

在模块上下文中记录对 nuxt.options 的修改,有助于调试模块在 Nuxt 初始化阶段所做的配置更改。

当启用 debug 模式时,此功能默认启用。如果你需要禁用此功能,也是可以做到的

要显式启用它

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    debugModuleMutation: true,
  },
})
有关实现细节,请参阅 PR #30555。

lazyHydration

这为 <Lazy> 组件启用了水合策略,通过将组件的水合延迟到实际需要时来提升性能。

延迟水合默认启用,但你可以禁用此功能

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    lazyHydration: false,
  },
})
阅读更多关于延迟水合的内容。

templateImportResolution

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

默认情况下,Nuxt 尝试相对于添加模板的模块来解析模板中的导入。将其设置为 false 将禁用此行为,如果你在某些环境中遇到解析冲突,这可能会很有用。

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

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    templateImportResolution: false,
  },
})
有关实现细节,请参阅 PR #31175。

templateRouteInjection

默认情况下,自动导入的 useRoute() 组合式函数返回的 route 对象与 <NuxtPage> 中当前可视的页面保持同步。对于 vue-router 导出的 useRoute 或 Vue 模板中可用的默认 $route 对象而言,并非如此。

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

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

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

decorators

此选项在你的整个 Nuxt/Nitro app 中启用装饰器(decorator)语法。

使用 Vite 构建器(默认)时,装饰器通过 Babel 并使用 @babel/plugin-proposal-decorators 进行降级(lowered)。当使用 webpack 或 rspack 构建器时,装饰器通过 esbuild 进行降级。

很长一段时间以来,TypeScript 一直通过 compilerOptions.experimentalDecorators 支持装饰器。该实现早于 TC39 标准化进程。现在,装饰器已成为一个 Stage 3 提案,并且在 TS 5.0+ 中无需特殊配置即可支持(参见 https://github.com/microsoft/TypeScript/pull/52582https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators)。

启用 experimental.decorators 启用的是对 TC39 提案的支持,而不是 TypeScript 先前的 compilerOptions.experimentalDecorators 实现。

请注意,在此功能最终写入 JS 标准之前,可能会有所更改。

使用

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

当使用 Vite 构建器或 Nitro 服务端构建时,你需要安装额外的 Babel 包作为开发依赖(dev dependencies)

npm install -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
如果这些包尚未存在,Nuxt 会提示你自动安装它们。
app/app.vue
function something (_method: () => unknown) {
  return () => 'decorated'
}

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

const value = new SomeClass().someMethod()
// this will return 'decorated'

defaults

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

这些选项将来可能会被移动到其他地方,例如 app.configapp/ 目录中。

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

useState.resetOnClear 选项控制 clearNuxtState 是将状态重置为其初始值(由 useStateinit 函数提供),还是将其设置为 undefined。在 compatibilityVersion: 5 下,此项默认为 true

purgeCachedData

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

Nuxt 会自动清除来自 useAsyncDatanuxtApp.static.data 的缓存数据。这有助于防止内存泄漏并确保在需要时加载最新数据,但你也可以将其禁用。

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

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    purgeCachedData: false,
  },
})
有关实现细节,请参阅 PR #31379。

prefetchPreloadTags

<NuxtLink> 被预获取且目标路由具有负载提取(payload extraction)启用时(预渲染和缓存路由的默认设置),将目标路由通过 useHead(或通过诸如 @nuxt/image<NuxtImg preload> 等模块)设置的任何 <link rel="preload"> 提示转发到当前文档中。

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

此标志默认关闭,因为结合 prefetchOn: 'visibility'<NuxtLink> 的默认值),它可能会同时触发大量跨路由预获取。当你确信目标预加载对于用户通常会遇到的链接来说值得转发时,再启用它。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    prefetchPreloadTags: true,
  },
})
有关动机,请参阅 issue #34953。

granularCachedData

useAsyncDatauseFetch 刷新数据时(无论是通过 watchrefreshNuxtData() 还是手动调用 refresh()),是否调用并使用 getCachedData 的结果。

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

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    granularCachedData: false,
  },
})
有关实现细节,请参阅 PR #31373。

headNext

使用 head 优化

  • 添加 capo.js head 插件,以便以更高性能的方式渲染 head 中的标签。
  • 使用哈希水合插件来减少初次水合

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

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

pendingWhenIdle

pendingWhenIdle 控制由 useAsyncDatauseFetch 返回的 pending ref。

pendingWhenIdlefalse(默认值)时,当请求正在进行中且匹配 status === 'pending' 时,pendingtrue。当 statusidle 时,pending 保持 false。你可以通过 { immediate: false } 或在服务端渲染期间通过 { server: false } 看到这一点。

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

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

entryImportMap

默认情况下,Nuxt 通过使用导入映射(import map)来解析 bundle 的入口代码块,从而提高代码块的稳定性。

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

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

在 Vite 发出的脚本代码块中,导入将来自 #entry。这意味着对入口的更改不会使其他未更改的代码块失效。

如果你已将 vite.build.target 配置为包含不支持导入映射的浏览器,或者你已将 vite.build.rolldownOptions.output.entryFileNames 配置为不包含 [hash] 的值,Nuxt 会智能地禁用此功能。

如果你需要禁用此功能,可以这样做

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    entryImportMap: false,
  },
  // or, better, simply tell vite your desired target
  // which nuxt will respect
  vite: {
    build: {
      target: 'safari13',
    },
  },
})

typescriptPlugin

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

此实验性插件提供了改进的 TypeScript 集成和开发工具,以便在 Nuxt 应用中使用 TypeScript 时获得更好的 DX(开发体验)。

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

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    typescriptPlugin: true,
  },
})
要使用此功能,你需要
  • typescript 安装为依赖项
  • 配置 VS Code 以使用你的工作区 TypeScript 版本(请参阅 VS Code 文档
了解更多关于 @dxup/nuxt 的信息。

viteEnvironmentApi

启用 Vite 6 的新 Environment API(环境 API)以改善构建配置和插件架构。

当你将 future.compatibilityVersion 设置为 5 时,此功能默认启用。你也可以出于测试目的显式启用它

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

Vite 环境 API 提供了开发构建与生产构建之间更好的连续性、对特定环境配置的更细粒度控制以及更高的性能。

启用此功能会更改 Vite 插件的注册和配置方式。有关更新插件的详细信息,请参阅 Vite 环境 API 迁移指南
了解更多关于 Vite 环境 API 的信息。

ssrStreaming

启用 SSR 流式传输以显著改善首字节时间 (TTFB)。启用后,服务器会立即发送 HTML 外壳(包括 <head>、样式、预加载提示和入口脚本),然后使用 Vue 的 renderToWebStream 逐步流式传输渲染好的正文内容。

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

对于机器人和爬虫用户代理(例如 Googlebot、Bingbot 等),流式传输会自动禁用,以确保搜索引擎收到完全渲染的 HTML 以保障 SEO 安全。默认模式仅匹配索引爬虫;Lighthouse 和其他审计工具故意排除在外,以便合成测量反映真实用户获得的相同流式响应。你可以自定义机器人检测正则表达式

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

你还可以使用 routeRules 按路由控制流式传输

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    ssrStreaming: true,
  },
  routeRules: {
    '/no-stream/**': { streaming: false },
  },
})
自动回退到非流式渲染。 一旦外壳(shell)刷新,流式传输就会提交响应状态和头部,这与渲染后需要修改响应的功能不兼容。匹配以下任一条件的请求不会进行流式传输;它们使用缓冲渲染器,或者短路跳转到重定向或错误响应
  • routeRules 为路由设置了 noScriptscacheisrswrredirectstreaming: false
  • ssr: false 路由(已经是 SPA 渲染)
  • 机器人/爬虫用户代理(通过 botRegex 控制)
  • 预渲染路由(nuxt generate
  • 来自插件、中间件或页面设置的服务端 navigateTo() 重定向
  • 初始渲染期间抛出的致命错误(在外壳刷新之前)
必须在外壳刷新之前设置响应状态和头部。 流式传输随第一个字节提交 HTTP 状态和头部,因此在那之后任何修改响应的操作都无法到达客户端。这是流式传输固有的特性,并非 Nuxt 特有的 bug。分界线就是外壳刷新
  • 能到达客户端:来自 Nuxt 和 Nitro 插件的修改,它们在渲染开始前运行完毕。
  • 丢弃:在组件渲染期间(包括在路由中间件或 <script setup> 中的 await 之后)进行的 setResponseStatus()useResponseHeader()useCookie() 写入以及 h3 的 setHeader()/appendResponseHeader() 调用,因为这些工作发生在外壳已经通过网络传输之后。
要保留响应修改,请将其移入插件,或者让路由退出流式传输
  • routeRules: { '/path': { streaming: false } }:静态的,按路由配置。
  • 带有 ctx.prefersStream = falserender:route 钩子:运行时的,按请求配置(例如针对条件性设置 404 的路由)。
在开发环境中,流式传输处理器会记录一条警告,指明被丢弃的修改和路由,因此这些操作绝不会静默失败。
如果在 HTTP 状态已经提交后流式传输期间发生错误,则会设置 payload.error,并且仍会输出闭合标签作为一个结构良好的文档,以便客户端在水合期间捕获该错误并渲染错误页面。在外壳刷新之前抛出的错误会落入缓冲错误渲染器,并带有正确的状态码。
路由样式会被流式传输,JS 提示仅限入口。 外壳在路由渲染之前刷新,因此其 <head> 仅携带入口代码块的样式和提示。一旦渲染注册了页面和布局模块,它们的 CSS 就会紧随外壳之后进行流式传输(启用 inlineStyles 时内联为 <style>,否则作为样式表链接),因此页面、布局和顶级异步组件的样式会在正文绘制之前到达(嵌套异步组件存在 FOUC 隐患,下文会涵盖)。路由专用的 JS 代码块不会从外壳预加载;浏览器在解析入口脚本后才会发现它们。流式传输可改善每个路由的 TTFB;LCP(最大内容绘制)的提升在 JS 与入口代码块重叠的路由上最大。
组件孤岛与流式传输兼容。 孤岛插槽内容和选择性客户端(nuxt-client)组件通常在渲染后阶段拼接到 HTML 中,一旦正文流式传输过了孤岛锚点,这是不可能做到的。相反,渲染器在文档末尾将每个孤岛传送(teleport)输出为一个惰性 <template>,并通过在水合之前运行的内联脚本将其重新定位到位。这对应用代码是透明的。例外情况是使用 features.noScripts 和孤岛组件构建的应用,由于重定位脚本无法运行,它们会回退到缓冲渲染器。

模块钩子

模块通过现有的 render:html 钩子(现在第二个参数上带有 streaming: true 标志)以及一个按请求决策钩子和两个仅流式传输的钩子参与流式响应

  • render:route 在每次请求渲染开始前触发一次,适用于每次渲染(无论是否启用流式传输)。读取 ctx.canStream 以查看该路由是否可以进行流式传输,并设置 ctx.prefersStream = false 以强制此请求使用缓冲渲染,例如基于 cookie、认证状态或 A/B 测试分桶。渲染器仅在 canStream && prefersStream 时进行流式传输。这是静态 routeRules / botRegex 配置的运行时逃生舱口。
  • render:html 在外壳刷新之前触发一次,其第二个参数带有 streaming: true。对 htmlAttrsheadbodyAttrsbodyPrepend 的修改会到达网络传输层。对 body/bodyAppend 的修改会被丢弃,因为正文即将流式传输(会发出开发模式警告)。仅修改 head 字段(CSP 注入、OG 标签、分析元数据)的模块在流式传输中无需更改代码即可工作。
  • render:html:chunk 在渲染器产生每个代码块并将其入队之前为其触发。修改 ctx.chunk: Uint8Array 以转换字节(例如 nonce 注入);读取 ctx.index 以区分第一个代码块与后续代码块。
  • render:html:close 在正文流完成之后、闭合标签之前触发。修改 ctx.bodyAppend: string[] 以注入最终的标记(正文末尾分析标签、服务端渲染的调试小部件等)。
// 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 }
    // Works for both streaming (pre-shell) and buffered (post-render) paths.
    for (let i = 0; i < ctx.head.length; i++) {
      ctx.head[i] = ctx.head[i].replace(/<script(?![^>]*\snonce=)/g, `<script nonce="${nonce}"`)
    }
  })
})
CSP nonce. 流式渲染器会输出几个绕过 unhead 的内联脚本和样式:引导队列、IIFE、suspense head 推送、孤岛传送重定位以及路由 <style> 块。如果渲染的 head 脚本上存在 nonce,渲染器会自动将其重用到所有这些脚本上,因此严格的 script-src/style-src 'nonce-…' 策略不会阻塞流式传输。模块只需要将 nonce 放在 head 脚本上(如上所述);render:html:chunk 钩子仍然可用于为组件渲染到正文中的脚本打上标记。
SFC 样式的开发模式 FOUC:在开发环境中,Vite 将 SFC <style> 块作为 JavaScript 模块提供,这些模块在求值后在客户端注入样式,shell 中没有相应的 <link>。使用流式传输时,浏览器会在这些样式注入模块运行之前开始渲染流式 DOM,因此 SFC 定义的样式会短暂地出现无样式闪烁。变通方法:将渲染关键样式放在通过 css: ['~/assets/main.css'] 注册的全局 CSS 文件中。全局 CSS 文件在 shell 的 <link rel="stylesheet"> 中输出(emitted),并在 body 内容流式传输之前应用。对于不影响初始渲染的组件级作用域样式,SFC <style> 块仍然适用。生产构建会将所有样式提取到真正的 CSS 文件中(或通过 features.inlineStyles 内联),因此这仅影响 nuxt dev。请使用 nuxt build && nuxt preview 验证流式传输的视觉效果。
嵌套异步组件的生产环境 FOUC:渲染器将路由 CSS 内联在紧跟 shell 之后发送的一个 chunk 中。它只能为此时模块已经注册的组件内联样式:页面、布局,以及直接放在 <Suspense> 边界内的任何异步组件(Vue 会在渲染开始时急切地实例化这些组件)。在另一个异步组件内部渲染的异步组件,只有在其父组件解析后(即第一个 chunk 流式传输之后)才会实例化。其 SFC <style> 错过了 shell 之后的样式 chunk,而是被输出在闭合的 HTML 中,位于组件自身 DOM 的后面。浏览器会无样式地渲染该组件,直到最后一个 chunk 到达。通过避免在深层嵌套的异步组件中使用渲染关键样式来规避此问题。
  • 将阻碍初始渲染的样式放在全局 CSS 文件中(css: ['~/assets/main.css']);这些样式会到达 shell 的 <head>
  • 使用原子类样式(Tailwind、UnoCSS):原子 CSS 位于入口样式表中,而不是每个组件的 <style> 块中。
  • 将拥有渲染关键 <style> 的异步组件直接放在 <Suspense> 边界下,而不是嵌套在另一个异步父组件后面。
  • 或者使用 routeRules: { '/path': { streaming: false } } 让路由退出流式传输。
嵌套异步组件上不影响初始渲染的作用域样式是没有问题的:短暂的闪烁只影响首屏内容。