要将 Nuxt 升级到最新版本,请使用 nuxt upgrade 命令。
npx nuxt upgrade
yarn nuxt upgrade
pnpm nuxt upgrade
bun x nuxt upgrade
要在发布前使用最新的 Nuxt 构建和测试功能,请阅读 夜间发布渠道 指南。
Nuxt 5 目前正在开发中。在发布之前,可以从 Nuxt 4.2+ 版本测试 Nuxt 5 的许多重大更改。
首先,将 Nuxt 升级到最新版本.
然后您可以设置您的 future.compatibilityVersion 以匹配 Nuxt 5 行为
export default defineNuxtConfig({
future: {
compatibilityVersion: 5,
},
})
当您将 future.compatibilityVersion 设置为 5 时,您的 Nuxt 配置中的默认设置将更改为选择 Nuxt v5 行为,包括
future.compatibilityVersion: 5 测试 Nuxt 5,请定期查看此处。重大或显著更改将在下面注明,并附带向后/向前兼容的迁移步骤。
🚦 影响级别:中
Nuxt 5 迁移到 Vite 6 的新环境 API,它规范了环境的概念,并为每个环境提供了更好的配置控制。
以前,Nuxt 使用单独的客户端和服务器 Vite 配置。现在,Nuxt 使用共享的 Vite 配置和环境特定的插件,这些插件使用 applyToEnvironment() 方法来定位特定环境。
future.compatibilityVersion: 5(参见 测试 Nuxt 5)或通过显式启用 experimental.viteEnvironmentApi: true 来提前测试此功能。主要更改
extendViteConfig():extendViteConfig() 中的 server 和 client 选项已废弃,使用时将显示警告。addVitePlugin() 注册的仅针对一个环境(通过传入 server: false 或 client: false)的 Vite 插件将不会调用其 config 或 configResolved 钩子。vite:extendConfig 和 vite:configResolved 钩子现在使用共享配置而不是单独的客户端/服务器配置。Vite 环境 API 提供
我们建议您使用 Vite 插件而不是 extendViteConfig、vite:configResolved 和 vite:extendConfig。
// Before
extendViteConfig((config) => {
config.optimizeDeps.include.push('my-package')
}, { server: false })
nuxt.hook('vite:extendConfig' /* or vite:configResolved */, (config, { isClient }) => {
if (isClient) {
config.optimizeDeps.include.push('my-package')
}
})
// After
addVitePlugin(() => ({
name: 'my-plugin',
config (config) {
// you can set global vite configuration here
},
configResolved (config) {
// you can access the fully resolved vite configuration here
},
configEnvironment (name, config) {
// you can set environment-specific vite configuration here
if (name === 'client') {
config.optimizeDeps ||= {}
config.optimizeDeps.include ||= []
config.optimizeDeps.include.push('my-package')
}
},
applyToEnvironment (environment) {
return environment.name === 'client'
},
}))
您可以使用插件中的新 applyToEnvironment 钩子,而不是使用带有 server: false 或 client: false 的 addVitePlugin。
// Before
addVitePlugin(() => ({
name: 'my-plugin',
config (config) {
config.optimizeDeps.include.push('my-package')
},
}), { client: false })
// After
addVitePlugin(() => ({
name: 'my-plugin',
config (config) {
// you can set global vite configuration here
},
configResolved (config) {
// you can access the fully resolved vite configuration here
},
configEnvironment (name, config) {
// you can set environment-specific vite configuration here
if (name === 'client') {
config.optimizeDeps ||= {}
config.optimizeDeps.include ||= []
config.optimizeDeps.include.push('my-package')
}
},
applyToEnvironment (environment) {
return environment.name === 'client'
},
}))
Nuxt 4 包含了显著的改进和更改。本指南将帮助您将现有的 Nuxt 3 应用程序迁移到 Nuxt 4。
首先,升级到 Nuxt 4
npm install nuxt@^4.0.0
yarn add nuxt@^4.0.0
pnpm add nuxt@^4.0.0
bun add nuxt@^4.0.0
升级后,大多数 Nuxt 4 行为现在是默认的。但是,如果您需要在迁移期间保持向后兼容性,仍然可以配置某些功能。
以下各节详细介绍了升级到 Nuxt 4 时所需的关键更改和迁移。
重大或显著更改将在下面记录,并附带迁移步骤和可用的配置选项。
为了简化升级过程,我们与Codemod团队合作,通过一些开源 codemods 自动化了许多迁移步骤。
npx codemod feedback 向 Codemod 团队报告 🙏有关 Nuxt 4 codemods 的完整列表、每个 codemod 的详细信息、其来源以及各种运行方式,请访问Codemod 注册表.
您可以使用以下 codemod 配方运行本指南中提到的所有 codemods
# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710
npx [email protected] nuxt/4/migration-recipe
# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710
yarn dlx [email protected] nuxt/4/migration-recipe
# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710
pnpm dlx [email protected] nuxt/4/migration-recipe
# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710
bun x [email protected] nuxt/4/migration-recipe
此命令将按顺序执行所有 codemods,您可以选择取消选择任何不想运行的 codemods。每个 codemod 也将在下面列出,并附带其各自的更改,并且可以独立执行。
🚦 影响级别:显著
Nuxt 现在默认使用新的目录结构,并向后兼容(因此,如果 Nuxt 检测到您正在使用旧结构,例如顶层 app/pages/ 目录,则此新结构将不适用)。
srcDir 默认为 app/,大多数内容都从那里解析。serverDir 现在默认为 <rootDir>/server,而不是 <srcDir>/serverlayers/、modules/ 和 public/ 默认相对于 <rootDir> 解析content/ RelativeTo <rootDir> 解析dir.app,它是我们查找 router.options.ts 和 spa-loading-template.html 的目录 - 它默认为 <srcDir>/.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/
shared/
server/
api/
middleware/
plugins/
routes/
utils/
nuxt.config.ts
~ 别名现在默认指向 app/ 目录(您的 srcDir)。这意味着 ~/components 解析为 app/components/,~/pages 解析为 app/pages/ 等等。👉 更多详情,请参见实现此更改的 PR.
.git/ 和 node_modules/ 文件夹被文件系统观察者扫描/包含,这可能会在非 Mac OS 上显著延迟启动。server/ 和应用程序的其余部分在两个完全不同的上下文中运行,具有不同的全局导入可用性,确保 server/ 不在应用程序其余部分所在的同一文件夹中是确保您在 IDE 中获得良好自动完成的第一步。app/ 的新目录。assets/、components/、composables/、app/layouts/、app/middleware/、app/pages/、app/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 应该会自动检测它。(如果未检测到,请提出问题。)唯一的例外是,如果您已经有一个自定义 srcDir。在这种情况下,您应该知道您的 modules/、public/ 和 server/ 文件夹将从您的 rootDir 而不是从您的自定义 srcDir 解析。如果需要,您可以通过配置 dir.modules、dir.public 和 serverDir 来覆盖此行为。
您还可以使用以下配置强制使用 v3 文件夹结构
export default defineNuxtConfig({
// This reverts the new srcDir default from `app` back to your root directory
srcDir: '.',
// This specifies the directory prefix for `router.options.ts` and `spa-loading-template.html`
dir: {
app: 'app',
},
})
🚦 影响级别:中等
Nuxt 的数据获取系统(useAsyncData 和 useFetch)已经过显著重组,以提高性能和一致性
useAsyncData 或 useFetch 的调用现在共享相同的 data、error 和 status 引用。这意味着所有具有显式键的调用都不能有冲突的 deep、transform、pick、getCachedData 或 default 选项。getCachedData 更多的控制:getCachedData 函数现在在每次获取数据时都会被调用,即使这是由观察者或调用 refreshNuxtData 引起的。(以前,在这种情况下总是获取新数据,并且不调用此函数。)为了更好地控制何时使用缓存数据以及何时重新获取,该函数现在接收一个包含请求原因的上下文对象。useAsyncData 获取数据的最后一个组件卸载时,Nuxt 将删除该数据以避免内存使用量不断增长。这些更改旨在改善内存使用并提高 useAsyncData 调用之间的加载状态一致性。
// This will now trigger a warning
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
useAsyncData 调用提取到它们自己的可组合函数中可能是有益的。export 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 - can be 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch'
+
+ // Example: Don't use cache on manual refresh
+ if (ctx.cause === 'refresh:manual') return undefined
+
+ return cachedData[key]
+ }
})
或者,目前,您可以使用以下方式禁用此行为
export default defineNuxtConfig({
experimental: {
granularCachedData: false,
purgeCachedData: false,
},
})
🚦 影响级别:最小
使用 Nuxt 层 时模块的加载顺序已更正。以前,项目根目录中的模块在扩展层中的模块之前加载,这与预期行为相反。
现在模块以正确的顺序加载
这会影响两者
nuxt.config.ts 中 modules 数组中定义的模块modules/ 目录自动发现的模块此更改确保
大多数项目不需要更改,因为这纠正了加载顺序以匹配预期行为。
但是,如果您的项目依赖于以前不正确的顺序,您可能需要
新正确顺序的示例
// Layer: my-layer/nuxt.config.ts
export default defineNuxtConfig({
modules: ['layer-module-1', 'layer-module-2'],
})
// Project: nuxt.config.ts
export default defineNuxtConfig({
extends: ['./my-layer'],
modules: ['project-module-1', 'project-module-2'],
})
// Loading order (corrected):
// 1. layer-module-1
// 2. layer-module-2
// 3. project-module-1 (can override layer modules)
// 4. project-module-2 (can override layer modules)
如果您由于需要注册钩子而遇到模块顺序依赖问题,请考虑使用 modules:done 钩子 来处理需要调用钩子的模块。此钩子在所有其他模块加载后运行,这意味着它是安全的。
👉 参见PR #31507等等问题 #25719获取更多详情。
🚦 影响级别:最小
可以使用 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,用于生成 <head> 标签,已更新到版本 2。虽然大部分兼容,但它包含几个对底层 API 的破坏性更改。
vmid、hid、children、body。上述更改对您的应用程序影响最小。
如果您遇到问题,您应该验证
useHead({
meta: [{
name: 'description',
// meta tags don't need a vmid, or a key
- vmid: 'description'
- hid: 'description'
}]
})
import { AliasSortingPlugin, TemplateParamsPlugin } 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'
如果您仍然遇到问题,可以通过启用 head.legacy 配置来恢复到 v1 行为。
export default defineNuxtConfig({
unhead: {
legacy: true,
},
})
🚦 影响级别:最小
当渲染仅客户端页面(带有 ssr: false)时,我们选择性地在 Nuxt 应用程序根目录下渲染一个加载屏幕(来自 ~/app/spa-loading-template.html - 请注意,在 Nuxt 4 中此文件也已更改为 ~/spa-loading-template.html)
<div id="__nuxt">
<!-- spa loading template -->
</div>
现在,我们默认在 Nuxt 应用程序根目录旁边渲染模板
<div id="__nuxt"></div>
<!-- spa loading template -->
这允许 spa 加载模板保留在 DOM 中,直到 Vue 应用程序的 suspense 解决,从而防止出现白屏闪烁。
如果您使用 CSS 或 document.queryElement 定位 spa 加载模板,您将需要更新您的选择器。为此,您可以使用新的 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>
🚦 影响级别:中等
Nuxt 现在只对 Vue 组件内联样式,而不是全局 CSS。
以前,Nuxt 会内联所有 CSS,包括全局样式,并移除 <link> 元素以分离 CSS 文件。现在,Nuxt 只会为 Vue 组件执行此操作(以前会生成单独的 CSS 块)。我们认为这更好地平衡了减少单独的网络请求(就像以前一样,初始加载时不会对每个页面或每个组件的单独 .css 文件发出单独请求),以及允许缓存单个全局 CSS 文件并减少初始请求的文档下载大小。
此功能完全可配置,您可以通过设置 inlineStyles: true 来恢复到以前的行为,以同时内联全局 CSS 和每个组件的 CSS。
export default defineNuxtConfig({
features: {
inlineStyles: true,
},
})
🚦 影响级别:最小
我们现在在调用 pages:extend 钩子之后而不是之前扫描页面元数据(在 definePageMeta 中定义)。
这是为了允许扫描用户希望在 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 数据。当预渲染使用 useAsyncData 或 useFetch 并在不同页面中获取相同数据的站点时,这可以显著提高性能。
例如,如果您的站点需要为每个页面调用 useFetch(例如,从 CMS 获取菜单导航数据或站点设置),则此数据只会在预渲染第一个使用它的页面时获取一次,然后缓存起来以供预渲染其他页面时使用。
确保您的数据的任何唯一键始终解析为相同的数据。例如,如果您使用 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 () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
// Instead, you should use a key that uniquely identifies the data fetched.
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 来自动化此步骤useAsyncData 和 useFetch 时 refresh 中 dedupe 选项的已废弃 boolean 值🚦 影响级别:最小
以前,可以将 dedupe: boolean 传递给 refresh。这些是 cancel (true) 和 defer (false) 的别名。
const { refresh } = await useAsyncData(() => Promise.resolve({ message: 'Hello, Nuxt!' }))
async function refreshData () {
await refresh({ dedupe: true })
}
为了更清晰,这些别名被移除。
当在 useAsyncData 的选项中添加 dedupe 时出现问题,我们移除了布尔值,因为它们最终是相反的。
refresh({ dedupe: false }) 意味着不要取消现有请求而优先于此新请求。但在 useAsyncData 的选项中传递 dedupe: true 意味着如果存在现有待处理请求,则不发送任何新请求。(参见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 中清除 data 时尊重默认值🚦 影响级别:最小
如果您为 useAsyncData 提供自定义的 default 值,那么在调用 clear 或 clearNuxtData 时将使用此值,它将被重置为其默认值,而不是简单地取消设置。
通常,用户会设置一个适当的空值,例如空数组,以避免在迭代时需要检查 null/undefined。在重置/清除数据时应遵守此规则。
useAsyncData 和 useFetch 中 pending 值对齐🚦 影响级别:中
从 useAsyncData、useFetch、useLazyAsyncData 和 useLazyFetch 返回的 pending 对象现在是一个计算属性,仅当 status 也处于 pending 状态时才为 true。
现在,当传入 immediate: false 时,pending 将为 false,直到发出第一个请求。这与以前的行为不同,以前 pending 始终为 true,直到发出第一个请求。
这使 pending 的含义与 status 属性对齐,status 属性在请求进行中时也处于 pending 状态。
如果您依赖 pending 属性,请确保您的逻辑考虑了新行为,即只有当状态也处于 pending 状态时,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 中的键更改行为🚦 影响级别:中
当在 useAsyncData 或 useFetch 中使用响应式键时,Nuxt 会在键更改时自动重新获取数据。当设置 immediate: false 时,useAsyncData 仅在键更改且数据已获取一次后才获取数据。
以前,useFetch 具有略微不同的行为。它会在键更改时总是获取数据。
现在,useFetch 和 useAsyncData 行为一致——只有当键更改且数据已经获取一次时才获取数据。
这确保了 useAsyncData 和 useFetch 之间行为一致,并防止意外获取。如果您已设置 immediate: false,则必须调用 refresh 或 execute,否则 useFetch 或 useAsyncData 将永远不会获取数据。
此更改通常会改善预期行为,但如果您期望更改非立即 useFetch 的键或选项,您现在将需要第一次手动触发它。
const id = ref('123')
const { data, execute } = await useFetch('/api/test', {
query: { id },
immediate: false
)
+ watch(id, () => execute(), { once: true })
要禁用此行为
// Or globally in your Nuxt config
export default defineNuxtConfig({
experimental: {
alwaysRunFetchOnKeyChange: true,
},
})
useAsyncData 和 useFetch 中的浅层数据响应性🚦 影响级别:最小
从 useAsyncData、useFetch、useLazyAsyncData 和 useLazyFetch 返回的 data 对象现在是 shallowRef 而不是 ref。
当获取新数据时,任何依赖于 data 的内容仍然会是响应式的,因为整个对象被替换了。但是,如果您的代码更改了该数据结构内部的属性,这不会触发应用程序中的任何响应性。
这为深度嵌套的对象和数组带来了显著的性能改进,因为 Vue 不需要监视每个单独的属性/数组的修改。在大多数情况下,data 也应该是不可变的。
在大多数情况下,不需要迁移步骤,但如果您依赖数据对象的响应性,则有两种选择
- const { data } = useFetch('/api/test')
+ const { data } = useFetch('/api/test', { deep: true })
export default defineNuxtConfig({
experimental: {
defaults: {
useAsyncData: {
deep: true,
},
},
},
})
npx codemod@latest nuxt/4/shallow-function-reactivity 来自动化此步骤builder:watch 中的绝对监听路径🚦 影响级别:最小
Nuxt builder:watch 钩子现在发出的是绝对路径,而不是相对于您的项目 srcDir 的路径。
这使我们能够支持监听 srcDir 之外的路径,并为层和其他更复杂的模式提供更好的支持。
我们已经主动迁移了我们知道使用此钩子的公共 Nuxt 模块。参见问题 #25339.
但是,如果您是模块作者,并且正在使用 builder:watch 钩子并希望保持向后/向前兼容,您可以使用以下代码确保您的代码在 Nuxt v3 和 Nuxt v4 中工作方式相同
+ 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__ 对象在应用程序完成水合后,我们将移除全局 window.__NUXT__ 对象。
这为多应用程序模式打开了道路(#21635),并使我们能够专注于一种访问 Nuxt 应用程序数据的方式——useNuxtApp()。
数据仍然可用,但可以通过 useNuxtApp().payload 访问
- console.log(window.__NUXT__)
+ console.log(useNuxtApp().payload)
🚦 影响级别:中
您的 app/middleware/ 文件夹中的子文件夹也会被扫描 index 文件,这些文件现在也注册为项目中的中间件。
Nuxt 会自动扫描许多文件夹,包括 app/middleware/ 和 app/plugins/。
您的 app/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 经历了一系列安全问题。这些问题实际上并不适用于 Nuxt 项目,因为它在构建时使用,而不是运行时使用,并且由受信任的代码使用。但是,它们仍然出现在安全审计中。此外,lodash 是一个庞大的依赖项,大多数项目都不使用它。
最后,直接在 Nuxt 中提供代码序列化函数并不理想。相反,我们维护像unjs/knitwork这样的项目,它们可以是您项目的依赖项,并且可以直接报告/解决安全问题,而无需升级 Nuxt 本身。
我们已经提出了 PR 来更新使用 EJS 语法的模块,但如果您需要自己执行此操作,您有三种向后/向前兼容的替代方案
getContents() 中。es-toolkit/compat(lodash 模板的直接替换),作为您项目的依赖项而不是 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 来自动化此步骤🚦 影响级别:最小
compilerOptions.noUncheckedIndexedAccess 现在是 true 而不是 false。
此更改是对之前3.12 配置更新的后续更改,我们改进了默认值,主要遵循TotalTypeScript 的建议.
有两种方法
nuxt.config.ts 中覆盖新默认值export default defineNuxtConfig({
typescript: {
tsConfig: {
compilerOptions: {
noUncheckedIndexedAccess: false,
},
},
},
})
🚦 影响级别:最小
Nuxt 现在为不同的上下文生成单独的 TypeScript 配置,以提供更好的类型检查体验
.nuxt/tsconfig.app.json - 用于您的应用程序代码(Vue 组件、组合式函数等).nuxt/tsconfig.server.json - 用于您的服务器端代码(Nitro/server 目录).nuxt/tsconfig.node.json - 用于您的构建时代码(模块、nuxt.config.ts 等).nuxt/tsconfig.shared.json - 用于应用程序和服务器上下文之间共享的代码(例如类型和非环境特定实用程序).nuxt/tsconfig.json - 用于向后兼容的旧配置.nuxt/tsconfig.json 的现有项目将继续像以前一样工作。typescript.nodeTsConfig 选项:您现在可以自定义 Node.js 构建时代码的 TypeScript 配置。此更改提供了多项优势
例如,自动导入在您的 nuxt.config.ts 中不可用(但以前 TypeScript 没有标记这一点)。虽然 IDE 识别出您的 server/ 目录中由 tsconfig.json 提示的独立上下文,但这并未反映在类型检查中(需要单独的步骤)。
无需迁移 - 现有项目将继续像以前一样工作。
但是,为了利用改进的类型检查,您可以选择新的项目引用方法
tsconfig.json 以使用项目引用tsconfig.json 当前有 "extends": "./.nuxt/tsconfig.json" 行,请在添加引用之前删除它。项目引用和 extends 是互斥的。{
// Remove "extends": "./.nuxt/tsconfig.json" if present
"files": [],
"references": [
{ "path": "./.nuxt/tsconfig.app.json" },
{ "path": "./.nuxt/tsconfig.server.json" },
{ "path": "./.nuxt/tsconfig.shared.json" },
{ "path": "./.nuxt/tsconfig.node.json" }
]
}
tsconfig.json 文件(例如 server/tsconfig.json)扩展了 .nuxt/tsconfig.server.json。- "typecheck": "nuxt prepare && vue-tsc --noEmit"
+ "typecheck": "nuxt prepare && vue-tsc -b --noEmit"
app/ 目录。server/ 目录。shared/ 目录。app/、server/ 或 shared/ 目录外部增强类型将不适用于新的项目引用设置。export default defineNuxtConfig({
typescript: {
// Customize app/server TypeScript config
tsConfig: {
compilerOptions: {
strict: true,
},
},
// Customize build-time TypeScript config
nodeTsConfig: {
compilerOptions: {
strict: true,
},
},
},
})
新配置为选择加入的项目提供了更好的类型安全和 IntelliSense,同时为现有设置保持了完全向后兼容。
🚦 影响级别:最小
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这些选项已经设置为当前值一段时间了,我们没有理由认为它们需要保持可配置。
generate 配置🚦 影响级别:最小
Nuxt 4 中不再提供顶层 generate 配置选项。这包括其所有属性
generate.exclude - 用于从预渲染中排除路由generate.routes - 用于指定要预渲染的路由顶层 generate 配置是 Nuxt 2 的遗留物。我们支持 nitro.prerender 已有一段时间,它是 Nuxt 3+ 中配置预渲染的首选方式。
将 generate 配置替换为相应的 nitro.prerender 选项
export default defineNuxtConfig({
- generate: {
- exclude: ['/admin', '/private'],
- routes: ['/sitemap.xml', '/robots.txt']
- }
+ nitro: {
+ prerender: {
+ ignore: ['/admin', '/private'],
+ routes: ['/sitemap.xml', '/robots.txt']
+ }
+ }
})
下表是 Nuxt 三个版本之间的快速比较
| 功能 / 版本 | Nuxt 2 | Nuxt Bridge | Nuxt 3+ |
|---|---|---|---|
| Vue | 2 | 2 | 3 |
| 稳定性 | 😊 稳定 | 😊 稳定 | 😊 稳定 |
| 性能 | 🏎 快 | ✈️ 更快 | 🚀 最快 |
| Nitro 引擎 | ❌ | ✅ | ✅ |
| ESM 支持 | 🌙 部分 | 👍 更好 | ✅ |
| TypeScript | ☑️ 选择加入 | 🚧 部分 | ✅ |
| 组合式 API | ❌ | 🚧 部分 | ✅ |
| Options API | ✅ | ✅ | ✅ |
| 组件自动导入 | ✅ | ✅ | ✅ |
<script setup> 语法 | ❌ | 🚧 部分 | ✅ |
| 自动导入 | ❌ | ✅ | ✅ |
| webpack | 4 | 4 | 5 |
| Vite | ⚠️ 部分 | 🚧 部分 | ✅ |
| Nuxt CLI | ❌ 旧 | ✅ nuxt | ✅ nuxt |
| 静态站点 | ✅ | ✅ | ✅ |
迁移指南提供了 Nuxt 2 功能与 Nuxt 3+ 功能的逐步比较,以及调整当前应用程序的指导。
如果您希望逐步将 Nuxt 2 应用程序迁移到 Nuxt 3,您可以使用 Nuxt Bridge。Nuxt Bridge 是一个兼容层,允许您通过选择加入机制在 Nuxt 2 中使用 Nuxt 3+ 功能。