实验特性
Nuxt 包含可以在配置文件中启用的实验性功能。
在内部,Nuxt 使用 @nuxt/schema 来定义这些实验性功能。您可以参考 API 文档 或 源码 以获取更多信息。
alwaysRunFetchOnKeyChange
当 key 发生变化时是否运行 useFetch,即使它被设置为 immediate: false 且尚未触发。
如果 immediate: true 或已经触发过,当 key 发生变化时,useFetch 和 useAsyncData 将始终运行。
此标志默认禁用,但你可以启用此功能:
export default defineNuxtConfig({
experimental: {
alwaysRunFetchOnKeyChange: true,
},
})
appManifest
使用应用清单在客户端遵循路由规则。
此标志默认启用,但你可以禁用此功能:
export default defineNuxtConfig({
experimental: {
appManifest: false,
},
})
asyncContext
启用原生异步上下文,使其可在 Nuxt 和 Nitro 中被嵌套的 composable 访问。这使得在异步 composable 中使用 composable 成为可能,并减少出现 Nuxt instance is unavailable 错误的概率。
export default defineNuxtConfig({
experimental: {
asyncContext: true,
},
})
asyncEntry
为 Vue 包生成异步入口点,以利于模块联邦(module federation)的支持。
export default defineNuxtConfig({
experimental: {
asyncEntry: true,
},
})
extractAsyncDataHandlers
从 useAsyncData 和 useLazyAsyncData 调用中提取处理函数到单独的块,以提高代码拆分和缓存效率。
export default defineNuxtConfig({
experimental: {
extractAsyncDataHandlers: true,
},
})
此功能将内联处理函数转换为动态导入的代码块:
<!-- 转换前 -->
<script setup>
const { data } = await useAsyncData('user', async () => {
return await $fetch('/api/user')
})
</script>
<!-- 转换后 -->
<script setup>
const { data } = await useAsyncData('user', () =>
import('/generated-chunk.js').then(r => r.default()),
)
</script>
这种转变的好处在于,我们可以将数据获取逻辑分离出来,同时仍然允许在需要时加载代码。
emitRouteChunkError
在加载 vite/webpack chunk 时发生错误时发出 app:chunkError 钩子。默认行为是在导航到新路由时,当 chunk 无法加载时重新加载新路由。
默认情况下,Nuxt 在导航到新路由时,如果 chunk 无法加载也会执行路由重载(automatic)。
设置为 automatic-immediate 将使 Nuxt 在 chunk 无法加载时立即对当前路由执行重载(而不是等待导航)。这对非导航触发的 chunk 错误很有用,例如当 Nuxt 应用无法加载懒加载组件。这种行为的一个潜在缺点是可能会导致不希望的重载,例如当应用并不需要导致错误的那部分 chunk 时。
您可以将其设置为 false 来禁用自动处理,或设置为 manual 以手动处理 chunk 错误。
export default defineNuxtConfig({
experimental: {
emitRouteChunkError: 'automatic', // 或 'automatic-immediate'、'manual' 或 false
},
})
enforceModuleCompatibility
当 Nuxt 模块不兼容时,是否应抛出错误并阻止加载。
此功能默认禁用。
export default defineNuxtConfig({
experimental: {
enforceModuleCompatibility: true,
},
})
restoreState
允许在发生 chunk 错误或手动调用 reloadNuxtApp() 后,从 sessionStorage 恢复 Nuxt 应用状态。
为了避免水合(hydration)错误,此操作仅在 Vue 应用挂载后应用,这意味着初次加载时可能会有闪烁现象。
useState 提供显式键,因为自动生成的键在不同构建间可能不匹配。export default defineNuxtConfig({
experimental: {
restoreState: true,
},
})
inlineRouteRules
使用 defineRouteRules 在页面级别定义路由规则。
export default defineNuxtConfig({
experimental: {
inlineRouteRules: true,
},
})
根据页面的 path 创建匹配的路由规则。
renderJsonPayloads
允许以支持恢复复杂类型的方式渲染 JSON payload。
此标志默认启用,但您可以禁用此功能:
export default defineNuxtConfig({
experimental: {
renderJsonPayloads: false,
},
})
noVueServer
在 Nitro 中禁用 Vue 服务端渲染器端点。
export default defineNuxtConfig({
experimental: {
noVueServer: true,
},
})
parseErrorData
compatibilityVersion: 5 时会强制启用该选项,设置它将被忽略。在渲染服务器错误页面时,是否解析 error.data。
之所以存在此选项,是因为错误之前会作为单独的查询参数传递给错误页面,这会将 error.data 转换为字符串,因此必须将其解析回来。将其设置为 false 可选择退出解析,并保留字符串形式。
现在,整个错误会进行 JSON 编码,因此 error.data 会以其原始结构传递,并且不会被转换为字符串。在 compatibilityVersion: 4 中,将此项设置为 false 会再次将其转换为字符串,以便调用 JSON.parse(error.data) 的现有错误页面继续正常工作:
export default defineNuxtConfig({
future: { compatibilityVersion: 4 },
experimental: {
parseErrorData: false,
},
})
payloadExtraction
控制如何为预渲染和缓存(ISR/SWR)页面交付 payload 数据。
'client'- Payload 会在初始服务端渲染时内联到 HTML 中,并在客户端导航时提取到_payload.json文件中。true- Payload 会在初始服务端渲染和客户端导航时都提取到单独的_payload.json文件中。false- 完全禁用 payload 提取。Payload 始终内联在 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,
},
})
early404
对于路径无法匹配任何页面路由的请求,提前返回 404 错误,而无需在服务器上加载 Vue 应用、其插件或中间件。
页面路由(包括别名)会在构建时编译为静态路由匹配器,并在服务端渲染开始前对传入请求进行检查。无法匹配任何页面的请求会完全跳过应用加载,直接前往错误页面。
不带有 Accept: text/html 标头的请求(API 客户端、大多数扫描器)会直接收到 JSON 错误,而完全不会加载应用。HTML 请求仍会对错误页面进行服务端渲染。覆盖该路径的 cache 路由规则 也会在 GET/HEAD 未命中时将其 maxAge 作为 Cache-Control 进行发布,使 CDN 能够吸收针对未知路径的重复请求。
export default defineNuxtConfig({
experimental: {
early404: true,
},
})
- 在插件中通过
router.addRoute()动态添加的页面。为尽早暴露此问题,启用此选项后,从useRouter返回的路由器类型中会移除addRoute。 - 将未知路径重定向到现有页面的路由中间件
hashMode 时、根级别的全捕获页面(例如 pages/[...slug].vue)匹配所有路径时,以及自定义 app/router.options 文件可能修改 routes 时,此选项会自动禁用(默认导出为不带 routes 键的普通对象的文件仍然兼容)。clientFallback
启用实验性的 <NuxtClientFallback> 组件,以便在 SSR 出错时在客户端渲染内容。
export default defineNuxtConfig({
experimental: {
clientFallback: true,
},
})
crossOriginPrefetch
使用 Speculation Rules API 启用跨域预取(cross-origin prefetch)。
export default defineNuxtConfig({
experimental: {
crossOriginPrefetch: true,
},
})
viewTransition
启用与客户端路由器的视图过渡 API 集成。export default defineNuxtConfig({
experimental: {
viewTransition: true,
},
})
export default defineNuxtConfig({
experimental: {
viewTransition: {
enabled: true,
types: ['slide'],
},
},
})
writeEarlyHints
在使用 Node 服务器时启用写入早期提示。export default defineNuxtConfig({
experimental: {
writeEarlyHints: true,
},
})
componentIslands
使用<NuxtIsland> 和 .island.vue 文件启用实验性的组件岛(component islands)支持。export default defineNuxtConfig({
experimental: {
componentIslands: true, // 也可为 false 或 'local+remote'
},
})
localLayerAliases
解析位于 layer 内的~、~~、@ 和 @@ 别名,相对于其 layer 的 source 和 root 目录进行解析。此标志默认启用,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
localLayerAliases: false,
},
})
typedPages
启用新的实验性类型化路由器。export default defineNuxtConfig({
experimental: {
typedPages: true,
},
})
navigateTo、<NuxtLink>、router.push() 等提供类型支持。您甚至可以通过在页面中使用 const route = useRoute('route-name') 来获得类型化的 params。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' 或 'builder'
},
})
sharedPrerenderData
Nuxt 会自动在预渲染的页面之间共享 payload data。当预渲染使用useAsyncData 或 useFetch,并且在不同页面中获取相同数据时,这可以显著提高性能。如果需要,您可以禁用此功能。export default defineNuxtConfig({
experimental: {
sharedPrerenderData: false,
},
})
useAsyncData 来获取与特定页面相关的数据,则应提供一个唯一对应于该数据的键。(useFetch 应会自动为您完成这一步。)// 这在动态页面(例如 `[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 自动为 Node.js 导入提供 polyfill。Buffer 这样的全局变量在浏览器中工作,您需要手动注入它们。import { Buffer } from 'node:buffer'
globalThis.Buffer ||= Buffer
scanPageMeta
Nuxt 在构建时向模块公开在definePageMeta 中定义的一些路由元数据(特别是 alias、name、path、redirect、props 和 middleware)。这仅适用于静态值或字符串/数组,而不适用于变量或条件赋值。有关更多信息和上下文,请参阅原始问题。默认情况下,页面元数据仅在 pages:extend 中所有路由注册完成后才会被扫描。然后会调用另一个钩子 pages:resolved。如果此功能在您的项目中造成问题,您可以禁用它。export default defineNuxtConfig({
experimental: {
scanPageMeta: false,
},
})
cookieStore
启用 CookieStore 支持以监听 cookie 更新(如果浏览器支持)并刷新useCookie 的 ref 值。此标志默认启用,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
cookieStore: false,
},
})
buildCache
基于配置和源文件的哈希缓存 Nuxt 构建产物。这仅适用于srcDir 和 serverDir 中的源文件,用于您应用的 Vue/Nitro 部分。此标志默认禁用,但您可以启用它: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 客户端/服务端包的重建。Nitro 将始终被重建(不过目前正在进行相关工作,以允许 Nitro 声明其可缓存的产物及其哈希)。checkOutdatedBuildInterval
设置检查新构建的时间间隔(以毫秒为单位)。当experimental.appManifest 为 false 时此功能被禁用。设置为 false 可禁用该检查。export default defineNuxtConfig({
experimental: {
checkOutdatedBuildInterval: 3600000, // 1 小时,或 false 表示禁用
},
})
extraPageMetaExtractionKeys
definePageMeta() 宏是收集页面构建时元数据的有用方式。Nuxt 本身提供了一组受支持的键列表,用于驱动一些内部功能,例如重定向、页面别名和自定义路径。此选项允许在使用 scanPageMeta 时传入额外的键以从页面元数据中提取。<script lang="ts" setup>
definePageMeta({
foo: 'bar',
})
</script>
export default defineNuxtConfig({
experimental: {
extraPageMetaExtractionKeys: ['foo'],
},
hooks: {
'pages:resolved' (ctx) {
// ✅ 现在可以访问 foo
},
},
})
NuxtPage 类型。extractSerializablePageMeta
当future.compatibilityVersion 为 5 或更高版本时默认启用。默认情况下,Nuxt 只会在构建时读取固定列表中的 definePageMeta() 键(以及 extraPageMetaExtractionKeys 中的任何内容);其他所有内容都会在运行时从为每个页面单独生成的模块中解析。启用此选项后,Nuxt 会直接将每个可序列化为 JSON 的属性写入生成的路由记录中。当页面的 definePageMeta() 中的所有属性都可以静态解析时,路由将完全不再导入该页面的元数据模块,从而使开发环境模块图中每个页面减少一个模块。<script lang="ts" setup>
definePageMeta({
layout: { name: 'admin', props: { collapsed: true } },
title: 'Dashboard',
})
</script>
scanPageMeta 为 false 时,此选项不会生效,因为此时路由记录不会覆盖元数据模块。export default defineNuxtConfig({
experimental: {
extractSerializablePageMeta: false,
},
})
navigationRepaint
在导航前等待一个动画帧,使浏览器有机会重绘以响应用户交互。在导航到预渲染路由时,这可以减少 INP。此标志默认启用,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
navigationRepaint: false,
},
})
navigateToEarlyReturn
将<script setup> 中顶层的 await navigateTo() 调用转换为已编译 setup() 函数中的提前返回,此操作仅在导航成功时发生。不启用此标志时,await navigateTo() 后的代码会继续运行,这可能导致后续代码(包括后续的 navigateTo 调用)覆盖重定向,或尝试渲染缺少数据的页面。启用此标志后,成功的导航会停止执行其余 setup 代码,并且组件会在导航继续进行时渲染一个占位符注释。此标志在 compatibilityVersion: 5 下默认启用,但您可以禁用它:export default defineNuxtConfig({
experimental: {
navigateToEarlyReturn: false,
},
})
<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> 中之后注册的任何生命周期钩子。normalizeComponentNames
Nuxt 更新自动生成的 Vue 组件名称,以匹配用于自动导入组件时的完整组件名。如果遇到问题,您可以禁用此功能。export default defineNuxtConfig({
experimental: {
normalizeComponentNames: false,
},
})
├─ components/
├─── SomeFolder/
├───── MyComponent.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 加载模板 -->
</div>
body 将模板与 Nuxt 应用根并列渲染:<div id="__nuxt"></div>
<!-- spa 加载模板 -->
browserDevtoolsTiming
为浏览器开发者工具启用 Nuxt 钩子的性能标记(performance markers)。这会在基于 Chromium 的浏览器的性能选项卡中添加可跟踪的性能标记,便于调试和优化性能。在开发模式下默认启用此功能。如果需要禁用,可以这样做:export default defineNuxtConfig({
experimental: {
browserDevtoolsTiming: false,
},
})
debugModuleMutation
记录模块上下文中对nuxt.options 的变更,以帮助调试 Nuxt 初始化阶段模块所做的配置更改。当启用 debug 模式时默认启用此功能。如果需要禁用,也可以这样做:要显式启用它:export default defineNuxtConfig({
experimental: {
debugModuleMutation: true,
},
})
lazyHydration
为<Lazy> 组件启用延迟水合(hydration)策略,通过延迟组件的水合来提高性能。默认启用延迟水合,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
lazyHydration: false,
},
})
templateImportResolution
禁用从添加模板的模块的路径解析 Nuxt 模板中的导入。默认情况下,Nuxt 会尝试将模板中的导入相对于添加它们的模块进行解析。将此设置为false 会禁用该行为,这在某些环境中遇到解析冲突时可能有用。此标志默认启用,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
templateImportResolution: false,
},
})
templateRouteInjection
默认情况下,自动导入的useRoute() composable 返回的路由对象会与 <NuxtPage> 中当前可见页面保持同步。对于 vue-router 导出的 useRoute 或 Vue 模板中可用的默认 $route 对象则不然。启用此选项将注入一个 mixin,以使模板中的 $route 对象与 Nuxt 管理的 useRoute() 保持同步。此标志默认启用,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
templateRouteInjection: false,
},
})
装饰器
此选项启用在整个 Nuxt/Nitro 应用中使用装饰器语法(decorator syntax),由 esbuild 驱动。长期以来,TypeScript 通过compilerOptions.experimentalDecorators 支持装饰器。该实现早于 TC39 标准化过程。现在,装饰器已成为一个 第 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,
},
})
@babel/plugin-proposal-decorators 插件来转译。使用 webpack 或 rspack 构建器时,装饰器通过 esbuild 进行转译。当使用 Vite 构建器或 Nitro 服务器构建时,您需要安装额外的 Babel 包作为开发依赖: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()
// 这里将返回 'decorated'
默认值
此项允许为核心 Nuxt 组件和 composable 指定默认选项。这些选项今后可能会被移到其他地方,例如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 的静态和 asyncData 缓存。Nuxt 将自动清除useAsyncData 和 nuxtApp.static.data 的缓存数据。这有助于防止内存泄漏并确保在需要时加载最新数据,但您也可以禁用此功能。此标志默认启用,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
purgeCachedData: false,
},
})
prefetchPreloadTags
当预取<NuxtLink> 且目标路由启用了 负载提取(预渲染和缓存路由的默认设置)时,会将目标通过 useHead(或通过 @nuxt/image 的 <NuxtImg preload> 等模块)设置的任何 <link rel="preload"> 提示转发到当前文档中。转发的链接会从 rel="preload" 降级为 rel="prefetch",因此它们不会与当前页面的关键资源竞争。只有用户定义的 head 标签会被转发;构建时的 JS/CSS chunk preload 已由预取管线单独处理。此标志默认关闭,因为它与 prefetchOn: 'visibility'(<NuxtLink> 的默认值)结合时,可能会一次性触发大量跨路由预取。只有当您确信目标预加载值得为用户通常遇到的链接进行转发时,再启用它。export default defineNuxtConfig({
experimental: {
prefetchPreloadTags: true,
},
})
granularCachedData
在刷新useAsyncData 和 useFetch 的数据时(无论是由 watch、refreshNuxtData() 还是手动调用 refresh() 触发),是否调用并使用 getCachedData 的结果。此标志默认启用,但您可以禁用此功能:export default defineNuxtConfig({
experimental: {
granularCachedData: false,
},
})
stripNeverHydratedData
默认将serialize: false 应用于在使用 hydrate-never 惰性 hydration 的组件内发起的 useAsyncData 和 useFetch 调用,以将它们的数据排除在 __NUXT_DATA__ 负载之外。由于这些组件在客户端上永远不会进行 hydration,因此它们的数据不需要用于 hydration。export default defineNuxtConfig({
experimental: {
stripNeverHydratedData: true,
},
})
serialize 选项始终具有优先级。如果相同的 key 与会进行 hydration 的组件共享,请在各次调用中保持 serialize 选项一致(Nuxt 会在开发环境中对不匹配发出警告)。headNext
使用头部优化:- 添加 capo.js head 插件,以更高效地渲染 head 中的标签。
- 使用 hash hydration 插件以减少初始水合。
export default defineNuxtConfig({
experimental: {
headNext: false,
},
})
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。当你的加载界面需要区分 idle 和正在进行中的请求时,请使用 status。export default defineNuxtConfig({
experimental: {
pendingWhenIdle: true,
},
})
entryImportMap
默认情况下,Nuxt 通过使用导入映射(import map)来解析 bundle 的入口 chunk,从而提高 chunk 的稳定性。这会在<head> 标签顶部注入一个导入映射:<script type="importmap">{"imports":{"#entry":"/_nuxt/DC5HVSK5.js"}}</script>
#entry。这意味着入口的更改不会使那些未改变的 chunk 失效。vite.build.target 配置为包含不支持导入映射的浏览器,或者将 vite.build.rollupOptions.output.entryFileNames 配置为不包含 [hash] 的值,Nuxt 会智能地禁用此功能。export default defineNuxtConfig({
experimental: {
entryImportMap: false,
},
// 或者,更好地告诉 Vite 您的目标环境
// Nuxt 将遵循此配置
vite: {
build: {
target: 'safari13',
},
},
})
typescriptPlugin
启用@dxup/nuxt 模块的增强 TypeScript 开发体验。这个实验性插件为在 Nuxt 应用中使用 TypeScript 提供了更好的集成和开发工具,以改善开发体验。此标志默认情况下是禁用的,但您可以启用此功能:export default defineNuxtConfig({
experimental: {
typescriptPlugin: true,
},
})
- 将
typescript安装为依赖项 - 配置 VS Code 以使用您的工作区 TypeScript 版本(请参阅 VS Code 文档)
ssrStreaming
启用 SSR 流式传输,以显著提升首字节时间(TTFB)。启用后,服务器会立即发送 HTML 外壳(包括<head>、样式、预加载提示和入口脚本),然后使用 Vue 的 renderToWebStream 逐步流式传输渲染后的主体内容。export default defineNuxtConfig({
experimental: {
ssrStreaming: true,
},
})
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 渲染)- Bot/爬虫用户代理(由
botRegex控制) - 预渲染路由(
nuxt generate) - 来自插件、中间件或页面 setup 的服务端
navigateTo()重定向 - 初始渲染期间抛出的致命错误(在外壳刷新之前)
- 会传递到客户端:来自 Nuxt 和 Nitro 插件的修改,它们在渲染开始前会运行完毕。
- 会被丢弃:在组件渲染期间进行的
setResponseStatus()、useResponseHeader()、useCookie()写入以及 h3 的setHeader()/appendResponseHeader()调用(包括在路由中间件或<script setup>中await之后),因为这些操作发生时外壳已经在传输中了。
routeRules: { '/path': { streaming: false } }:静态的、按路由配置。- 带有
ctx.prefersStream = false的render:route钩子:运行时、按请求配置(例如用于有条件设置 404 的路由)。
payload.error,并且闭合标签仍会作为一个格式完整的文档发出,以便客户端在水合期间捕获错误并渲染错误页面。在外壳刷新之前抛出的错误会落入缓冲错误渲染器,并带有正确的状态码。<head> 只包含入口 chunk 的样式和提示。一旦渲染注册了页面和布局模块,它们的 CSS 会紧随外壳之后直接流式传输(在启用 inlineStyles 时以内联 <style> 形式,否则以样式表链接形式),因此页面、布局和顶层异步组件的样式会在主体绘制之前到达(嵌套异步组件存在 FOUC 注意事项,见下文)。特定路由的 JS chunk 不会从外壳中预加载;浏览器会在解析入口脚本后发现它们。流式传输会提升每条路由的 TTFB;对于 JS 与入口 chunk 重叠的路由,LCP 收益最大。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在渲染器生成每个 chunk 并将其入队前触发。修改ctx.chunk: Uint8Array以转换字节(例如注入 nonce);读取ctx.index以识别第一个 chunk 与后续 chunk。render:html:close在主体流完成后、闭合标签之前触发。修改ctx.bodyAppend: string[]以注入最终标记(body 末尾的分析标签、服务端渲染的调试小部件等)。
// 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 }
// 同时适用于流式(外壳前)和缓冲(渲染后)路径。
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 模块提供,这些模块在模块求值后由客户端注入样式,而不会在外壳中生成对应的 <link>。在流式传输下,浏览器会在这些样式注入模块运行之前开始绘制流式 DOM,因此 SFC 定义的样式会短暂地闪烁为无样式。解决方法:将对首屏渲染至关重要的样式放入通过 css: ['~/assets/main.css'] 注册的全局 CSS 文件中。全局 CSS 文件会作为 <link rel="stylesheet"> 在外壳 <head> 中发出,并在主体内容流式传输前生效。SFC <style> 块仍然适合用于不影响初始绘制的组件级样式。生产构建会将所有样式提取为真实的 CSS 文件(或通过 features.inlineStyles 进行内联),因此这只影响 nuxt dev。请使用 nuxt build && nuxt preview 验证流式传输下的视觉效果。<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 } }让该路由退出流式传输。