升级指南
升级 Nuxt
最新版本
要将 Nuxt 升级到最新版本,请使用 nuxt upgrade
命令。
npx nuxt upgrade
yarn nuxt upgrade
pnpm nuxt upgrade
bun x nuxt upgrade
每日构建版本渠道
要在新特性发布前使用最新的 Nuxt 构建并进行测试,请阅读 每日构建版本渠道 指南。
latest
标签目前跟踪 Nuxt v4 分支,这意味着现在特别可能存在破坏性更改 —— 请务必小心!你可以通过 "nuxt": "npm:nuxt-nightly@3x"
选择使用 3.x 分支的每日构建版本。测试 Nuxt 4
Nuxt 4 计划于 2025 年第二季度发布。它将包含所有当前通过 compatibilityVersion: 4
可用的功能。
在正式发布之前,可以从 Nuxt 3.12 版本开始测试许多 Nuxt 4 的破坏性更改。
选择使用 Nuxt 4
首先,将 Nuxt 升级到最新版本。
然后,你可以设置 compatibilityVersion
来匹配 Nuxt 4 的行为:
export default defineNuxtConfig({
future: {
compatibilityVersion: 4,
},
// 若要重新启用 _全部_ Nuxt v3 的行为,请设置以下选项:
// srcDir: '.',
// dir: {
// app: 'app'
// },
// experimental: {
// scanPageMeta: 'after-resolve',
// sharedPrerenderData: false,
// compileTemplate: true,
// resetAsyncDataToUndefined: true,
// templateUtils: true,
// relativeWatchPaths: true,
// normalizeComponentNames: false,
// spaLoadingTemplateLocation: 'within',
// parseErrorData: false,
// pendingWhenIdle: true,
// alwaysRunFetchOnKeyChange: true,
// defaults: {
// useAsyncData: {
// deep: true
// }
// }
// },
// features: {
// inlineStyles: true
// },
// unhead: {
// renderSSRHeadOptions: {
// omitLineBreaks: false
// }
// }
})
compatibilityVersion
。在 Nuxt 4 发布后,将不再需要这样做。当你将 compatibilityVersion
设置为 4
时,Nuxt 配置中的默认值将更改以适应 Nuxt v4 行为,但你可以根据上面注释的行内容,在测试中逐步重新启用 Nuxt v3 的行为。如果遇到问题,请提交 issue,方便我们在 Nuxt 或生态系统中修复。
重大或破坏性变更将会在这里进行说明,并提供向前/向后兼容的迁移步骤。
compatibilityVersion: 4
测试 Nuxt 4,请定期回来查看。使用 Codemods 迁移
为了简化升级流程,我们与 Codemod 团队合作,提供了一些开源的代码转换工具(codemods)来自动执行许多迁移步骤。
npx codemod feedback
向 Codemod 团队反馈 🙏有关完整的 Nuxt 4 codemods 列表、每个工具的详细信息、源码和多种运行方式,请访问 Codemod 注册表。
你可以使用以下 codemod
命令执行本指南中提到的所有 codemods:
npx codemod@latest nuxt/4/migration-recipe
yarn dlx codemod@latest nuxt/4/migration-recipe
pnpm dlx codemod@latest nuxt/4/migration-recipe
bun x codemod@latest nuxt/4/migration-recipe
该命令将会按顺序运行所有 codemods,你还可以选择不执行某些不想运行的;每个 codemod 也在下文列出,并可单独运行。
新的目录结构
🚦 影响等级:重大
Nuxt 默认采用新的目录结构,但保持向后兼容(如果 Nuxt 检测到你使用的是旧结构,比如顶级的 pages/
目录,则不会应用这个新结构)。
变化内容
- 新的 Nuxt 默认
srcDir
现在是app/
,大部分内容都从这里解析。 serverDir
默认从<rootDir>/server
而非<srcDir>/server
layers/
、modules/
和public/
目录默认相对于<rootDir>
解析- 如果使用 Nuxt Content v2.13+,
content/
相对于<rootDir>
解析 - 新增
dir.app
,这是寻找router.options.ts
和spa-loading-template.html
的目录,默认是<srcDir>/
示例 v4 文件夹结构
.output/
.nuxt/
app/
assets/
components/
composables/
layouts/
middleware/
pages/
plugins/
utils/
app.config.ts
app.vue
router.options.ts
content/
layers/
modules/
node_modules/
public/
server/
api/
middleware/
plugins/
routes/
utils/
nuxt.config.ts
👉 详情可见 实现此变更的 PR。
变更原因
- 性能 - 把代码全部放在项目根目录会导致
.git/
和node_modules/
文件夹被文件系统监听器扫描/包含,这可能在非 macOS 系统上显著延长启动时间。 - IDE 类型安全 -
server/
目录与应用其余部分运行在两个完全不同的环境中,拥有不同的全局导入。确保server/
不在应用程序其余部分的相同目录中是实现 IDE 良好自动补全的第一大步。
迁移步骤
- 创建一个名为
app/
的新目录。 - 将你的
assets/
、components/
、composables/
、layouts/
、middleware/
、pages/
、plugins/
和utils/
文件夹移到其中,以及app.vue
、error.vue
、app.config.ts
。如果你已有app/router-options.ts
或app/spa-loading-template.html
,路径保持不变。 - 确保
nuxt.config.ts
、content/
、layers/
、modules/
、public/
和server/
文件夹留在项目根目录(app/
外)。 - 记得更新任何第三方配置文件以适应新的目录结构,比如你的
tailwindcss
或eslint
配置(如果需要的话,@nuxtjs/tailwindcss
会自动配置正确的tailwindcss
)。
npx codemod@latest nuxt/4/file-structure
来自动化此迁移。然而,迁移 非必需。如果想继续使用当前的文件夹结构,Nuxt 会自动检测。如果没有检测到,请提交 issue。唯一的例外是如果你已经自定义了 srcDir
。此时,你需要知道 modules/
、public/
和 server/
文件夹会从你的 rootDir
解析,而不是从自定义的 srcDir
。如有需要,你可通过配置 dir.modules
、dir.public
和 serverDir
来覆盖。
你也可以通过以下配置强制使用 v3 文件夹结构:
export default defineNuxtConfig({
// 将新的 srcDir 默认值从 `app` 改回根目录
srcDir: '.',
// 指定 `app/router.options.ts` 和 `app/spa-loading-template.html` 的目录前缀
dir: {
app: 'app'
}
})
单例数据获取层
🚦 影响等级:中等
变化内容
Nuxt 的数据获取系统 (useAsyncData
和 useFetch
) 已经被大幅重构,以提升性能和一致性:
- 相同 key 共享 refs:所有调用
useAsyncData
或useFetch
并使用相同 key 的调用都会共享同一份data
、error
和status
refs。这意味着所有带显式 key 的调用的选项deep
、transform
、pick
、getCachedData
或default
不能冲突。 - 对
getCachedData
更多控制:现在无论数据是否来自 watcher 还是通过调用refreshNuxtData
,每次请求数据时都会调用getCachedData
。之前这些场景下会强制重新获取数据而不调用该函数。为了更灵活地控制何时使用缓存数据,函数接收的上下文参数中包含了请求来源。 - 支持响应式 key:现在可使用计算的 refs、普通 refs 或 getter 函数作为 key,从而支持自动数据刷新(并分开存储数据)。
- 数据清理:当最后一个使用了某条
useAsyncData
获取数据的组件卸载时,Nuxt 会移除这条数据,避免内存持续增长。
变更原因
这些修改是为了改善内存使用效率和提升多个调用之间加载状态的一致性。
迁移步骤
- 检查不一致的选项:审查任何对相同 key 使用不一致选项或获取函数的组件。
// 这将触发警告 const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false }) const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
建议将对同一明确 key 的调用(同时含自定义选项)提取到独立的组合函数中:composables/useUserData.tsexport function useUserData(userId: string) { return useAsyncData( `user-${userId}`, () => fetchUser(userId), { deep: true, transform: (user) => ({ ...user, lastAccessed: new Date() }) } ) }
- 更新
getCachedData
的实现:useAsyncData('key', fetchFunction, { - getCachedData: (key, nuxtApp) => { - return cachedData[key] - } + getCachedData: (key, nuxtApp, ctx) => { + // ctx.cause - 可能是 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch' + + // 例子:手动刷新时不使用缓存 + if (ctx.cause === 'refresh:manual') return undefined + + return cachedData[key] + } })
你也可以通过以下配置关闭该行为:
export default defineNuxtConfig({
experimental: {
granularCachedData: false,
purgeCachedData: false
}
})
路由元数据去重
🚦 影响等级:最低
变化内容
可以通过 definePageMeta
设置部分路由元数据,例如 name
、path
等。以前这些信息既存在于路由对象上,也存在于路由元数据中(例如,route.name
与 route.meta.name
)。
现在,这些属性仅可通过路由对象访问。
变更原因
这是因为默认启用了 experimental.scanPageMeta
,是性能优化措施。
迁移步骤
迁移比较简单:
const route = useRoute()
- console.log(route.meta.name)
+ console.log(route.name)
组件名称规范化
🚦 影响等级:中等
Vue 现在会生成符合 Nuxt 组件命名规范的组件名称。
变化内容
如果你没有手动设置组件名称,Vue 默认会将组件名称设为组件的文件名。
├─ components/
├─── SomeFolder/
├───── MyComponent.vue
在 Vue 中,该组件名称为 MyComponent
。你如果想在 <KeepAlive>
中使用,或者在 Vue DevTools 中识别它,就会用这个名称。
但为了自动导入,你必须使用 SomeFolderMyComponent
。
现在这两个名称将会统一,Vue 会生成与 Nuxt 组件命名模式匹配的组件名称。
迁移步骤
请确保在所有使用 @vue/test-utils
中的 findComponent
的测试以及所有依赖组件名称的 <KeepAlive>
标签中,使用了更新后的名称。
你也可以暂时通过以下配置关闭该行为:
export default defineNuxtConfig({
experimental: {
normalizeComponentNames: false
}
})
Unhead v2
🚦 影响等级:最低
变化内容
用于生成 <head>
标签的 Unhead 更新至版本 2。虽然大多数兼容,但底层 API 有若干破坏性变更:
- 移除了属性:
vmid
、hid
、children
、body
。 - 不再支持 Promise 类型输入。
- 标签排序默认使用 Capo.js。
迁移步骤
上述变更对你的应用影响较小。
确保你没有使用已移除的属性。
useHead({
meta: [{
name: 'description',
// meta 标签不再需要 vmid 或 key
- vmid: 'description'
- hid: 'description'
}]
})
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'
export default defineNuxtPlugin({
setup() {
const unhead = injectHead()
unhead.use(TemplateParamsPlugin)
unhead.use(AliasSortingPlugin)
}
})
虽非必须,推荐将 @unhead/vue
的引入改为 #imports
或 nuxt/app
。
-import { useHead } from '@unhead/vue'
+import { useHead } from '#imports'
如果仍有问题,可通过开启旧版模式恢复 v1 行为:
export default defineNuxtConfig({
unhead: {
legacy: true,
}
})
SPA 加载屏幕的新 DOM 位置
🚦 影响等级:最低
变化内容
在渲染仅客户端页面(ssr: false
)时,Nuxt 会在 Nuxt 应用根节点内渲染加载屏幕(取自 app/spa-loading-template.html
):
<div id="__nuxt">
<!-- spa loading template -->
</div>
现在,默认将加载模板渲染在 Nuxt 应用根节点旁边:
<div id="__nuxt"></div>
<!-- spa loading template -->
变更原因
这样做可确保加载模板保留在 DOM 中,直到 Vue 应用的 Suspense 解析完成,避免白屏闪烁。
迁移步骤
如果你使用 CSS 或 document.querySelector
选中加载模板,需要更新选择器。你可以使用新的 app.spaLoaderTag
和 app.spaLoaderAttrs
配置选项来辅助。
此外可用以下配置恢复之前行为:
export default defineNuxtConfig({
experimental: {
spaLoadingTemplateLocation: 'within',
}
})
error.data
解析
🚦 影响等级:最低
之前抛出的错误对象中的 data
属性未被解析。现在它被解析后可在 error
对象中使用。虽然这是修正,但如果依赖旧行为并自己解析,则属于破坏性变更。
迁移步骤
更新自定义的 error.vue
,移除对 error.data
的额外解析:
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps({
error: Object as () => NuxtError
})
- const data = JSON.parse(error.data)
+ const data = error.data
</script>
你也可以通过关闭该实验特性:
export default defineNuxtConfig({
experimental: {
parseErrorData: false
},
})
更精细的内联样式
🚦 影响等级:中等
变化内容
Nuxt 现在只对 Vue 组件内联样式,而非所有全局 CSS。
以前,Nuxt 会将全部 CSS(包括全局样式)内联,并移除 <link>
外链;现在仅对 Vue 组件内联 CSS(这些组件之前会拆分独立 CSS chunk)。这在减少网络请求(首屏不请求单独 .css
文件)的同时,支持缓存单一全局 CSS 文件,减小初始文档大小。
迁移步骤
此特性可配置,你可以通过设置 inlineStyles: true
恢复之前的全局样式内联行为:
export default defineNuxtConfig({
features: {
inlineStyles: true
}
})
延后扫描页面元数据
🚦 影响等级:最低
变化内容
现在扫描页面元数据(由 definePageMeta
定义)是在调用 pages:extend
钩子后进行,而非之前的钩子之前。
变更原因
这样可扫描用户在 pages:extend
中新增的页面元数据。我们还增加了一个新的钩子 pages:resolved
,供你修改或覆盖元数据。
迁移步骤
如果你想覆盖页面元数据,应在 pages:resolved
钩子中完成,而非 pages:extend
。
export default defineNuxtConfig({
hooks: {
- 'pages:extend'(pages) {
+ 'pages:resolved'(pages) {
const myPage = pages.find(page => page.path === '/')
myPage.meta ||= {}
myPage.meta.layout = 'overridden-layout'
}
}
})
你也可以用以下配置恢复之前行为:
export default defineNuxtConfig({
experimental: {
scanPageMeta: true
}
})
共享预渲染数据
🚦 影响等级:中等
变化内容
启用了之前的实验特性:在不同页面间共享 useAsyncData
和 useFetch
调用的数据。详情见原始 PR。
变更原因
此特性允许预渲染时在页面间共享 payload 数据,显著提升重复请求相同数据的站点性能,比如每个页面都需要调用 useFetch
获取导航栏数据时,首次获取后缓存用于其他页面。
迁移步骤
确保所有数据唯一的 key 均能映射到对应数据。例如,在动态页面中,useAsyncData
的 key 应能唯一标识获取的数据:
// 这是不安全的,因为路由参数 slug 影响数据,但 key 没反映这一点。
const route = useRoute()
const { data } = await useAsyncData(async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
// 应该使用能唯一标识数据的key。
const { data } = await useAsyncData(route.params.slug, async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
你也可以关闭该功能:
export default defineNuxtConfig({
experimental: {
sharedPrerenderData: false
}
})
useAsyncData
和 useFetch
中默认的 data
和 error
值
🚦 影响等级:最低
变化内容
useAsyncData
返回的 data
和 error
对象默认值现在是 undefined
。
变更原因
之前 data
初始化为 null
,但在 clearNuxtData
时重置为 undefined
,error
初始化为 null
。此变更更一致。
迁移步骤
如你之前检查 data.value
或 error.value
是否为 null
,请改为检查 undefined
。
npx codemod@latest nuxt/4/default-data-error-value
自动执行此步骤。出现问题可通过以下配置恢复旧行为:
export default defineNuxtConfig({
experimental: {
defaults: {
useAsyncData: {
value: 'null',
errorValue: 'null'
}
}
}
})
如采用此配置请反馈问题,我们计划不再支持此配置。
useAsyncData
和 useFetch
中调用 refresh
时 dedupe
选项的布尔值支持 移除
🚦 影响等级:最低
变化内容
之前可以向 refresh
传递 dedupe: boolean
,与 cancel: true
和 defer: false
别名相同。
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt!' }))
async function refreshData () {
await refresh({ dedupe: true })
}
变更原因
为了更清晰,移除了布尔值别名。
因为 refresh({ dedupe: false })
表示 不取消 当前请求;但 dedupe: true
在 useAsyncData
选项中表示如果已有未完成请求则不新建请求,两者含义是 相反 的。(详见 PR)
迁移步骤
迁移比较简单:
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' }))
async function refreshData () {
- await refresh({ dedupe: true })
+ await refresh({ dedupe: 'cancel' })
- await refresh({ dedupe: false })
+ await refresh({ dedupe: 'defer' })
}
npx codemod@latest nuxt/4/deprecated-dedupe-value
自动执行此步骤。useAsyncData
和 useFetch
清理数据时遵守默认值
🚦 影响等级:最低
变化内容
为 useAsyncData
提供了自定义的 default
值后,调用 clear
或 clearNuxtData
时会用该默认值重置,而非直接清空。
变更原因
很多用户使用合适的空值(例如空数组)避免在访问数据时检查 null
或 undefined
,应该尊重并保持这类默认值。
迁移步骤
遇问题时可临时用此配置恢复旧行为:
export default defineNuxtConfig({
experimental: {
resetAsyncDataToUndefined: true,
}
})
此配置未来可能移除,使用时请反馈。
useAsyncData
和 useFetch
中 pending
值对齐
🚦 影响等级:中等
useAsyncData
、useFetch
、useLazyAsyncData
及 useLazyFetch
返回的 pending
现在是一个计算属性,仅当 status
处于 pending 状态时为 true。
变化内容
当设置 immediate: false
时,pending
会在首次请求发起前保持 false,之前是始终 true。
变更原因
pending
现在与 status
属性意义对齐,均表示请求正在进行。
迁移步骤
依赖 pending
的逻辑需考虑新行为,pending
只在 status
pending 时为 true。
<template>
- <div v-if="!pending">
+ <div v-if="status === 'success'">
<p>Data: {{ data }}</p>
</div>
<div v-else>
<p>Loading...</p>
</div>
</template>
<script setup lang="ts">
const { data, pending, execute, status } = await useAsyncData(() => fetch('/api/data'), {
immediate: false
})
onMounted(() => execute())
</script>
你也可临时恢复旧行为:
export default defineNuxtConfig({
experimental: {
pendingWhenIdle: true
}
})
useAsyncData
和 useFetch
中 key 变更行为
🚦 影响等级:中等
变化内容
使用响应式 key 时,Nuxt 在 key 变化时自动重新获取数据。immediate: false
时,useAsyncData
仅在已有数据的情况下才会在 key 变更时重新请求。
之前 useFetch
行为略不同,总是在 key 变更时请求数据。
现在,useFetch
和 useAsyncData
行为统一,仅在已有数据的情况下响应 key 变化。
变更原因
统一两者行为,避免意外请求。若设置 immediate: false
,必须调用 refresh
或 execute
才能拉取数据。
迁移步骤
新行为通常是提升体验,但若之前依赖 useFetch
在 key 变化时自动请求,首次需手动触发:
const id = ref('123')
const { data, execute } = await useFetch('/api/test', {
query: { id },
immediate: false
)
+ watch(id, execute, { once: true })
可全局禁用该行为:
// 或在 Nuxt 配置中
export default defineNuxtConfig({
experimental: {
alwaysRunFetchOnKeyChange: true
}
})
useAsyncData
和 useFetch
中的数据浅层响应性
🚦 影响等级:最低
useAsyncData
、useFetch
、useLazyAsyncData
及 useLazyFetch
返回的 data
现在是 shallowRef
而非 ref
。
变化内容
新数据到达时,替换 data
对象会触发响应。但修改 data
内部属性不再触发响应。
变更原因
极大提升深层嵌套对象和数组的性能,因为 Vue 不再监听每个属性的变化。大多数场景数据应保持不可变。
迁移步骤
多数情况无需变动,若依赖深层响应,可选:
- 针对特定组合函数启用深层响应:
- const { data } = useFetch('/api/test') + const { data } = useFetch('/api/test', { deep: true })
- 全局默认开启(不推荐):nuxt.config.ts
export default defineNuxtConfig({ experimental: { defaults: { useAsyncData: { deep: true } } } })
npx codemod@latest nuxt/4/shallow-function-reactivity
自动执行此步骤。builder:watch
中的绝对路径监听
🚦 影响等级:最低
变化内容
builder:watch
钩子现在发出的路径为绝对路径(而非相对于 srcDir
的相对路径)。
变更原因
支持监听 srcDir
以外的路径,更好支持层(layers)及复杂场景。
迁移步骤
我们已主动迁移知晓的公共 Nuxt 模块,详见 issue #25339。
作为模块作者,想保持兼容可按以下方式保证:
+ import { relative, resolve } from 'node:fs'
// ...
nuxt.hook('builder:watch', async (event, path) => {
+ path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path))
// ...
})
npx codemod@latest nuxt/4/absolute-watch-path
window.__NUXT__
对象 移除
变化内容
应用完成 hydration 后全局对象 window.__NUXT__
被移除。
变更原因
为多应用模式铺路(#21635),并聚焦通过单一方式访问 Nuxt 应用数据 —— useNuxtApp()
。
迁移步骤
数据依旧可用,只需改为访问:
- console.log(window.__NUXT__)
+ console.log(useNuxtApp().payload)
目录索引扫描改进
🚦 影响等级:中等
变化内容
middleware/
目录下的子文件夹同样扫描 index
文件,并将其注册为中间件。
变更原因
为使 middleware/
和 plugins/
目录的行为一致,后者子文件夹已有类似行为。
迁移步骤
一般不需要迁移,若想恢复旧行为,可使用钩子过滤掉 index
中间件:
export default defineNuxtConfig({
hooks: {
'app:resolve'(app) {
app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path))
}
}
})
模板编译变更
🚦 影响等级:最低
变化内容
以前 Nuxt 使用 lodash/template
来编译基于文件系统的模板(.ejs
语法)。
同时提供了一些模板工具函数(serialize
、importName
、importSources
),现在移除这些内容。
变更原因
Nuxt v3 引入了支持 getContents()
的“虚拟”语法,更灵活且高效。
lodash/template
存在多个安全问题,虽然在构建时调用、由可信代码使用,但仍引发安全审计。lodash 是较大依赖,许多项目不使用。
由 Nuxt 内置提供代码序列化也不理想。我们提供了诸如 unjs/knitwork 这样的项目,可作为项目依赖,便于独立修复安全问题。
迁移步骤
我们已提交 PR 更新使用 EJS 语法的模块,你也可选择以下三种兼容方案:
- 将字符串插值逻辑转入
getContents()
。 - 使用自定义替换函数,如 https://github.com/nuxt-modules/color-mode/pull/240。
- 使用
es-toolkit/compat
(lodash template 的无缝替代),作为你项目依赖而非 Nuxt 依赖:
+ import { readFileSync } from 'node:fs'
+ import { template } from 'es-toolkit/compat'
// ...
addTemplate({
fileName: 'appinsights-vue.js'
options: { /* some options */ },
- src: resolver.resolve('./runtime/plugin.ejs'),
+ getContents({ options }) {
+ const contents = readFileSync(resolver.resolve('./runtime/plugin.ejs'), 'utf-8')
+ return template(contents)({ options })
+ },
})
若你使用了模板工具函数(serialize
、importName
、importSources
),可改用 knitwork
函数:
import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"{(.+)}"(?=,?$)/gm, r => JSON.parse(r).replace(/^{(.*)}$/, '$1'))
const importSources = (sources: string | string[], { lazy = false } = {}) => {
return toArray(sources).map((src) => {
if (lazy) {
return `const ${genSafeVariableName(src)} = ${genDynamicImport(src, { comment: \`webpackChunkName: \${JSON.stringify(src)}\` })}`
}
return genImport(src, genSafeVariableName(src))
}).join('\n')
}
const importName = genSafeVariableName
npx codemod@latest nuxt/4/template-compilation-changes
自动执行该迁移。移除实验性特性的配置项
🚦 影响等级:最低
变化内容
以下四个实验特性在 Nuxt 4 中不再可配置:
experimental.treeshakeClientOnly
默认为true
(v3.0 起默认)experimental.configSchema
默认为true
(v3.3 起默认)experimental.polyfillVueUseHead
默认为false
(v3.4 起默认)experimental.respectNoSSRHeader
默认为false
(v3.4 起默认)vite.devBundler
不可配置,默认使用vite-node
变更原因
这些选项已长期保持此默认值,且无理由继续保留可配置性。
迁移步骤
Nuxt 2 与 Nuxt 3+ 对比
下表快速对比了 Nuxt 三个版本:
功能 / 版本 | Nuxt 2 | Nuxt Bridge | Nuxt 3+ |
---|---|---|---|
Vue 版本 | 2 | 2 | 3 |
稳定性 | 😊 稳定 | 😊 稳定 | 😊 稳定 |
性能 | 🏎 快 | ✈️ 更快 | 🚀 最快 |
Nitro 引擎 | ❌ | ✅ | ✅ |
ESM 支持 | 🌙 部分支持 | 👍 较好 | ✅ |
TypeScript 支持 | ☑️ 可选 | 🚧 部分支持 | ✅ |
Composition API | ❌ | 🚧 部分支持 | ✅ |
Options API | ✅ | ✅ | ✅ |
组件自动导入 | ✅ | ✅ | ✅ |
<script setup> 语法 | ❌ | 🚧 部分支持 | ✅ |
自动导入 | ❌ | ✅ | ✅ |
webpack 版本 | 4 | 4 | 5 |
Vite 支持 | ⚠️ 部分支持 | 🚧 部分支持 | ✅ |
Nuxt CLI | ❌ 老版本 | ✅ nuxt | ✅ nuxt |
静态站点支持 | ✅ | ✅ | ✅ |
从 Nuxt 2 迁移到 Nuxt 3+
迁移指南提供了 Nuxt 2 特性与 Nuxt 3+ 特性的逐步对比,以及如何适配现有应用的指导。
从 Nuxt 2 迁移到 Nuxt Bridge
如果你希望渐进迁移 Nuxt 2 应用到 Nuxt 3,可以使用 Nuxt Bridge。Nuxt Bridge 是一个兼容层,允许你在 Nuxt 2 中按需启用 Nuxt 3+ 的特性。