实验性功能
Nuxt 包含可以在配置文件中启用的实验性功能。
在内部,Nuxt 使用 @nuxt/schema 来定义这些实验性功能。有关更多信息,您可以参考 API 文档或源代码。
alwaysRunFetchOnKeyChange
当 key 改变时是否运行 useFetch,即使它被设置为 immediate: false 且尚未被触发。
如果设置了 immediate: true 或者已经被触发过,当 key 改变时,useFetch 和 useAsyncData 将始终运行。
此标志默认禁用,但你可以启用此功能
export default defineNuxtConfig({
experimental: {
alwaysRunFetchOnKeyChange: true,
},
})
appManifest
使用应用清单(app manifests)在客户端遵守路由规则。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
appManifest: false,
},
})
asyncContext
启用原生的异步上下文,以便 Nuxt 和 Nitro 中的嵌套组合式函数可以访问。这使得在异步组合式函数内部使用组合式函数成为可能,并减少出现 Nuxt instance is unavailable(Nuxt 实例不可用)错误的机会。
export default defineNuxtConfig({
experimental: {
asyncContext: true,
},
})
asyncEntry
启用 Vue bundle 的异步入口点生成,从而辅助模块联邦(module federation)支持。
export default defineNuxtConfig({
experimental: {
asyncEntry: true,
},
})
externalVue
在构建时将 vue、@vue/* 和 vue-router 外部化(externalize)。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
externalVue: false,
},
})
extractAsyncDataHandlers
将 useAsyncData 和 useLazyAsyncData 调用中的处理函数提取到单独的代码块(chunks)中,以提高代码分割和缓存效率。
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>
这种转换的好处是我们可以分离出数据获取逻辑,同时在需要时仍然允许加载代码。
emitRouteChunkError
当加载 vite/webpack 代码块(chunks)出错时,触发 app:chunkError 钩子。默认行为是:当导航到新路由且代码块加载失败时,重新加载新路由。
默认情况下,在导航到新路由时,如果代码块加载失败,Nuxt 也会重新加载新路由(automatic)。
设置 automatic-immediate 会导致 Nuxt 在代码块加载失败时立即重新加载当前路由(而不是等待导航)。这对于不由导航触发的代码块错误非常有用,例如当你的 Nuxt 应用加载延迟组件失败时。这种行为的一个潜在缺点是可能会产生不需要的重新加载,例如当你的应用实际上不需要导致错误的代码块时。
你可以通过将此项设置为 false 来禁用自动处理,或者通过将其设置为 manual 来手动处理代码块错误。
export default defineNuxtConfig({
experimental: {
emitRouteChunkError: 'automatic', // or 'automatic-immediate', 'manual' or false
},
})
enforceModuleCompatibility
如果 Nuxt 模块不兼容,Nuxt 是否应抛出错误(并加载失败)。
此功能默认禁用。
export default defineNuxtConfig({
experimental: {
enforceModuleCompatibility: true,
},
})
restoreState
允许在代码块错误或手动调用 reloadNuxtApp() 后重新加载页面时,从 sessionStorage 恢复 Nuxt 应用状态。
为避免水合(hydration)错误,它仅在 Vue 应用挂载后应用,这意味着初次加载时可能会有闪烁。
useState 提供显式键,因为自动生成的键可能在不同的构建之间不匹配。export default defineNuxtConfig({
experimental: {
restoreState: true,
},
})
inlineRouteRules
使用 defineRouteRules 在页面级别定义路由规则。
export default defineNuxtConfig({
experimental: {
inlineRouteRules: true,
},
})
将根据页面的 path 创建匹配的路由规则。
renderJsonPayloads
允许渲染 JSON 负载,并支持恢复(revivifying)复杂类型。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
renderJsonPayloads: false,
},
})
noVueServer
禁用 Nitro 中的 Vue 服务端渲染器端点。
export default defineNuxtConfig({
experimental: {
noVueServer: true,
},
})
parseErrorData
渲染服务端错误页面时是否解析 error.data。
此标志默认启用,但你可以禁用此功能
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。
export default defineNuxtConfig({
experimental: {
payloadExtraction: 'client',
},
})
clientNodePlaceholder
在服务端渲染期间,使用注释节点(<!--placeholder-->)而不是 <div> 元素作为仅客户端组件的占位符。
启用后,.client.vue 组件和 createClientOnly() 包装器在服务端渲染一个 HTML 注释,而不是一个空的 <div>。这修复了一个 Vue 水合问题:当占位符 <div> 与实际组件根节点具有相同的标签名时,作用域样式可能不会被应用。
.client.vue 组件的属性(class、style 等)不会出现在 SSR HTML 中。如果你需要带样式的占位符来防止布局偏移,请改用带有 #fallback 插槽的 <ClientOnly>。当 future.compatibilityVersion 设置为 5 或更高版本时,此标志会自动启用,但你也可以显式启用它
export default defineNuxtConfig({
experimental: {
clientNodePlaceholder: true,
},
})
clientFallback
启用实验性的 <NuxtClientFallback> 组件,以便在 SSR 发生错误时在客户端渲染内容。
export default defineNuxtConfig({
experimental: {
clientFallback: true,
},
})
crossOriginPrefetch
使用推测规则 API(Speculation Rules API)启用跨域预获取。
export default defineNuxtConfig({
experimental: {
crossOriginPrefetch: true,
},
})
viewTransition
启用视图过渡 API(View Transition API)与客户端路由器的集成。
export default defineNuxtConfig({
experimental: {
viewTransition: true,
},
})
你还可以传递一个对象来配置 视图过渡类型(view transition types),这允许根据导航类型使用不同的 CSS 动画
export default defineNuxtConfig({
experimental: {
viewTransition: {
enabled: true,
types: ['slide'],
},
},
})
writeEarlyHints
在使用 node 服务器时启用早期提示(early hints)的写入。
export default defineNuxtConfig({
experimental: {
writeEarlyHints: true,
},
})
componentIslands
通过 <NuxtIsland> 和 .island.vue 文件启用实验性的组件孤岛(component islands)支持。
export default defineNuxtConfig({
experimental: {
componentIslands: true, // false or 'local+remote'
},
})
localLayerAliases
根据层源目录和根目录解析位于各层(layers)中的 ~、~~、@ 和 @@ 别名。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
localLayerAliases: false,
},
})
typedPages
启用新的实验性类型化路由(typed router)。
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.compatibilityVersion 为 5 时成为默认设置。如果活动构建器未实现自己的监视器(目前 webpack 和 rspack),Nuxt 会记录一条警告并回退到其默认选择。
export default defineNuxtConfig({
experimental: {
watcher: 'chokidar-granular', // 'chokidar', 'parcel' or 'builder' are also options
},
})
sharedPrerenderData
Nuxt 会自动在预渲染的页面之间共享负载数据。当预渲染使用 useAsyncData 或 useFetch 并在不同页面中获取相同数据的网站时,这可以显著提升性能。
如果需要,你可以禁用此功能。
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 中定义的一些路由元数据(具体为 alias、name、path、redirect、props 和 middleware)。
这仅适用于静态值、字符串或数组,而不适用于变量或条件赋值。有关更多信息和背景,请参阅 原始 issue。
默认情况下,页面元数据仅在所有路由都在 pages:extend 中注册后才会扫描。然后会调用另一个钩子 pages:resolved。
如果此功能在你的项目中引发问题,你可以将其禁用。
export default defineNuxtConfig({
experimental: {
scanPageMeta: false,
},
})
cookieStore
启用 CookieStore 支持以监听 cookie 更新(如果浏览器支持)并刷新 useCookie 的 ref 值。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
cookieStore: false,
},
})
buildCache
根据配置和源文件的哈希值缓存 Nuxt 构建产物。
这仅适用于应用中 Vue/Nitro 部分的 srcDir 和 serverDir 内的源文件。
此标志默认禁用,但你可以启用它
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 声明其可缓存产物及其哈希值)。
checkOutdatedBuildInterval
设置检查新构建的时间间隔(以毫秒为单位)。当 experimental.appManifest 为 false 时禁用。
设置为 false 以禁用。
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 类型。
navigationRepaint
在导航前等待单个动画帧,这为浏览器提供了重新绘制的机会,以响应用户交互。
它可以在预渲染路由上导航时减少 INP(Interaction to Next Paint)。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
navigationRepaint: false,
},
})
normalizeComponentNames
Nuxt 会更新自动生成的 Vue 组件名称,以匹配你用于自动导入该组件的全组件名。
如果你遇到问题,可以禁用此功能。
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.vue 和 pages/bar/index.vue 的组件名都将是 index。这使得基于名称的 <KeepAlive> 过滤不可靠,因为多个页面共享相同的名称。
启用 normalizePageNames 后,页面组件将以其路由命名(例如 foo 和 bar),因此你可以将 <KeepAlive> 与 include/exclude 一起使用,而无需手动向每个页面添加 defineOptions({ name: '...' })。
当 future.compatibilityVersion 设置为 5 或更高版本时,此标志会自动启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
normalizePageNames: false,
},
})
<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)”标签页中进行跟踪,这对于调试和优化性能非常有用。
这在开发模式下默认启用。如果你需要禁用此功能,也是可以做到的
export default defineNuxtConfig({
experimental: {
browserDevtoolsTiming: false,
},
})
debugModuleMutation
在模块上下文中记录对 nuxt.options 的修改,有助于调试模块在 Nuxt 初始化阶段所做的配置更改。
当启用 debug 模式时,此功能默认启用。如果你需要禁用此功能,也是可以做到的
要显式启用它
export default defineNuxtConfig({
experimental: {
debugModuleMutation: true,
},
})
lazyHydration
这为 <Lazy> 组件启用了水合策略,通过将组件的水合延迟到实际需要时来提升性能。
延迟水合默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
lazyHydration: false,
},
})
templateImportResolution
禁用从添加模板的模块路径解析 Nuxt 模板中的导入。
默认情况下,Nuxt 尝试相对于添加模板的模块来解析模板中的导入。将其设置为 false 将禁用此行为,如果你在某些环境中遇到解析冲突,这可能会很有用。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
templateImportResolution: false,
},
})
templateRouteInjection
默认情况下,自动导入的 useRoute() 组合式函数返回的 route 对象与 <NuxtPage> 中当前可视的页面保持同步。对于 vue-router 导出的 useRoute 或 Vue 模板中可用的默认 $route 对象而言,并非如此。
通过启用此选项,将注入一个混入(mixin),以使 $route 模板对象与 Nuxt 管理的 useRoute() 保持同步。
此标志默认启用,但你可以禁用此功能
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/52582 和 https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators)。
启用 experimental.decorators 启用的是对 TC39 提案的支持,而不是 TypeScript 先前的 compilerOptions.experimentalDecorators 实现。
使用
export default defineNuxtConfig({
experimental: {
decorators: true,
},
})
当使用 Vite 构建器或 Nitro 服务端构建时,你需要安装额外的 Babel 包作为开发依赖(dev dependencies)
npm install -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
pnpm add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
yarn add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
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.config 或 app/ 目录中。
export default defineNuxtConfig({
experimental: {
defaults: {
nuxtLink: {
componentName: 'NuxtLink',
prefetch: true,
prefetchOn: {
visibility: true,
},
},
useAsyncData: {
deep: true,
},
useState: {
resetOnClear: true,
},
},
},
})
useState.resetOnClear 选项控制 clearNuxtState 是将状态重置为其初始值(由 useState 的 init 函数提供),还是将其设置为 undefined。在 compatibilityVersion: 5 下,此项默认为 true。
purgeCachedData
在路由导航时是否清理 Nuxt 的 static 和 asyncData 缓存。
Nuxt 会自动清除来自 useAsyncData 和 nuxtApp.static.data 的缓存数据。这有助于防止内存泄漏并确保在需要时加载最新数据,但你也可以将其禁用。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
purgeCachedData: false,
},
})
prefetchPreloadTags
当 <NuxtLink> 被预获取且目标路由具有负载提取(payload extraction)启用时(预渲染和缓存路由的默认设置),将目标路由通过 useHead(或通过诸如 @nuxt/image 的 <NuxtImg preload> 等模块)设置的任何 <link rel="preload"> 提示转发到当前文档中。
转发的链接从 rel="preload" 降级为 rel="prefetch",这样它们就不会与当前页面的关键资源竞争。仅转发用户定义的 head 标签;构建时的 JS/CSS 代码块预加载已由预获取管道单独处理。
此标志默认关闭,因为结合 prefetchOn: 'visibility'(<NuxtLink> 的默认值),它可能会同时触发大量跨路由预获取。当你确信目标预加载对于用户通常会遇到的链接来说值得转发时,再启用它。
export default defineNuxtConfig({
experimental: {
prefetchPreloadTags: true,
},
})
granularCachedData
为 useAsyncData 和 useFetch 刷新数据时(无论是通过 watch、refreshNuxtData() 还是手动调用 refresh()),是否调用并使用 getCachedData 的结果。
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
granularCachedData: false,
},
})
headNext
使用 head 优化
- 添加 capo.js head 插件,以便以更高性能的方式渲染 head 中的标签。
- 使用哈希水合插件来减少初次水合
此标志默认启用,但你可以禁用此功能
export default defineNuxtConfig({
experimental: {
headNext: false,
},
})
pendingWhenIdle
pendingWhenIdle 控制由 useAsyncData 和 useFetch 返回的 pending ref。
当 pendingWhenIdle 为 false(默认值)时,当请求正在进行中且匹配 status === 'pending' 时,pending 为 true。当 status 为 idle 时,pending 保持 false。你可以通过 { immediate: false } 或在服务端渲染期间通过 { server: false } 看到这一点。
将 pendingWhenIdle: true 设置为 true,这样当 status 为 idle 且没有可用的缓存数据时,pending 也为 true。当你的加载 UI 需要区分 idle 和进行中的请求时,请使用 status。
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 会智能地禁用此功能。如果你需要禁用此功能,可以这样做
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(开发体验)。
此标志默认禁用,但你可以启用此功能
export default defineNuxtConfig({
experimental: {
typescriptPlugin: true,
},
})
- 将
typescript安装为依赖项 - 配置 VS Code 以使用你的工作区 TypeScript 版本(请参阅 VS Code 文档)
viteEnvironmentApi
启用 Vite 6 的新 Environment API(环境 API)以改善构建配置和插件架构。
当你将 future.compatibilityVersion 设置为 5 时,此功能默认启用。你也可以出于测试目的显式启用它
export default defineNuxtConfig({
experimental: {
viteEnvironmentApi: true,
},
})
Vite 环境 API 提供了开发构建与生产构建之间更好的连续性、对特定环境配置的更细粒度控制以及更高的性能。
ssrStreaming
启用 SSR 流式传输以显著改善首字节时间 (TTFB)。启用后,服务器会立即发送 HTML 外壳(包括 <head>、样式、预加载提示和入口脚本),然后使用 Vue 的 renderToWebStream 逐步流式传输渲染好的正文内容。
export default defineNuxtConfig({
experimental: {
ssrStreaming: true,
},
})
对于机器人和爬虫用户代理(例如 Googlebot、Bingbot 等),流式传输会自动禁用,以确保搜索引擎收到完全渲染的 HTML 以保障 SEO 安全。默认模式仅匹配索引爬虫;Lighthouse 和其他审计工具故意排除在外,以便合成测量反映真实用户获得的相同流式响应。你可以自定义机器人检测正则表达式
export default defineNuxtConfig({
experimental: {
ssrStreaming: {
botRegex: /googlebot|bingbot|my-internal-crawler/i,
},
},
})
你还可以使用 routeRules 按路由控制流式传输
export default defineNuxtConfig({
experimental: {
ssrStreaming: true,
},
routeRules: {
'/no-stream/**': { streaming: false },
},
})
routeRules为路由设置了noScripts、cache、isr、swr、redirect或streaming: falsessr: false路由(已经是 SPA 渲染)- 机器人/爬虫用户代理(通过
botRegex控制) - 预渲染路由(
nuxt generate) - 来自插件、中间件或页面设置的服务端
navigateTo()重定向 - 初始渲染期间抛出的致命错误(在外壳刷新之前)
- 能到达客户端:来自 Nuxt 和 Nitro 插件的修改,它们在渲染开始前运行完毕。
- 丢弃:在组件渲染期间(包括在路由中间件或
<script setup>中的await之后)进行的setResponseStatus()、useResponseHeader()、useCookie()写入以及 h3 的setHeader()/appendResponseHeader()调用,因为这些工作发生在外壳已经通过网络传输之后。
routeRules: { '/path': { streaming: false } }:静态的,按路由配置。- 带有
ctx.prefersStream = false的render:route钩子:运行时的,按请求配置(例如针对条件性设置 404 的路由)。
payload.error,并且仍会输出闭合标签作为一个结构良好的文档,以便客户端在水合期间捕获该错误并渲染错误页面。在外壳刷新之前抛出的错误会落入缓冲错误渲染器,并带有正确的状态码。<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。对htmlAttrs、head、bodyAttrs和bodyPrepend的修改会到达网络传输层。对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}"`)
}
})
})
<style> 块。如果渲染的 head 脚本上存在 nonce,渲染器会自动将其重用到所有这些脚本上,因此严格的 script-src/style-src 'nonce-…' 策略不会阻塞流式传输。模块只需要将 nonce 放在 head 脚本上(如上所述);render:html:chunk 钩子仍然可用于为组件渲染到正文中的脚本打上标记。<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 验证流式传输的视觉效果。<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 } }让路由退出流式传输。