升级指南

了解如何升级到最新的 Nuxt 版本。

升级 Nuxt

最新版本

要将 Nuxt 升级到最新版本,请使用 nuxt upgrade 命令。

npx nuxt upgrade

夜版发布渠道

要使用 Nuxt 的最新构建版本并测试新功能(尚未正式发布),请阅读夜版发布渠道指南。

测试 Nuxt 5

Nuxt 5 目前正在开发中。在发布之前,可以测试许多 Nuxt 5 从 Nuxt 版本 4.2+ 的重大更改。

选择使用 Nuxt 5

首先,将 Nuxt 升级到 最新版本

然后,您可以将 future.compatibilityVersion 设置为匹配 Nuxt 5 的行为:

nuxt.config.ts
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 5,
  },
})

当您将 future.compatibilityVersion 设置为 5 时,您在 Nuxt 配置中的默认值将更改为选择 Nuxt v5 的行为,包括:

本节内容在最终发布之前可能会有所更改,因此如果您正在使用 future.compatibilityVersion: 5 测试 Nuxt 5,请定期回来查看。

重大或显著的变化将在下面注明,并附上向后/向前兼容的迁移步骤。

迁移到 Vite 环境 API

🚦 影响级别:中等

变化内容

Nuxt 5 迁移到 Vite 6 的新 环境 API,该 API 正式化了环境的概念,并提供了对每个环境配置的更好控制。

之前,Nuxt 使用单独的客户端和服务器 Vite 配置。现在,Nuxt 使用共享的 Vite 配置,并配备特定于环境的插件,这些插件使用 applyToEnvironment() 方法来针对特定环境。

Vite 环境 API 在 Nuxt 5 中始终启用。experimental.viteEnvironmentApi 选项已被移除。

关键变化:

  1. 不再支持特定于环境的 extendViteConfig()extendViteConfig() 中的 serverclient 选项已被弃用,使用时将显示警告。
  2. 更改插件注册:使用 addVitePlugin() 注册的 Vite 插件,如果仅针对一个环境(通过传递 server: falseclient: false)将不会调用其 configconfigResolved 钩子。
  3. 共享配置vite:extendConfigvite:configResolved 钩子现在与共享配置一起工作,而不是单独的客户端/服务器配置。

变更原因

Vite 环境 API 提供了:

  • 更好的一致性,确保开发和生产构建之间的差异最小化
  • 更细粒度的环境特定配置控制
  • 改进的性能和插件架构
  • 支持自定义环境,而不仅仅是客户端和服务器

迁移步骤

1. 迁移到使用 Vite 插件

我们建议您使用 Vite 插件,而不是 extendViteConfigvite:configResolvedvite:extendConfig

// 之前
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')
  }
})

// 之后
addVitePlugin(() => ({
  name: 'my-plugin',
  config (config) {
    // 这里可以设置全局 vite 配置
  },
  configResolved (config) {
    // 这里可以访问完整解析后的 vite 配置
  },
  configEnvironment (name, config) {
    // 这里可以设置特定环境的 vite 配置
    if (name === 'client') {
      config.optimizeDeps ||= {}
      config.optimizeDeps.include ||= []
      config.optimizeDeps.include.push('my-package')
    }
  },
  applyToEnvironment (environment) {
    return environment.name === 'client'
  },
}))
2. 迁移 Vite 插件以使用环境

您可以使用插件中的新 applyToEnvironment 钩子,而不是使用 addVitePlugin 结合 server: falseclient: false

// 之前
addVitePlugin(() => ({
  name: 'my-plugin',
  config (config) {
    config.optimizeDeps.include.push('my-package')
  },
}), { client: false })

// 之后
addVitePlugin(() => ({
  name: 'my-plugin',
  config (config) {
    // 这里可以设置全局 vite 配置
  },
  configResolved (config) {
    // 这里可以访问完整解析后的 vite 配置
  },
  configEnvironment (name, config) {
    // 这里可以设置特定环境的 vite 配置
    if (name === 'client') {
      config.optimizeDeps ||= {}
      config.optimizeDeps.include ||= []
      config.optimizeDeps.include.push('my-package')
    }
  },
  applyToEnvironment (environment) {
    return environment.name === 'client'
  },
}))
了解更多关于 Vite 环境 API 的内容

迁移到 Vite 8

🚦 影响级别:中等

变化内容

Nuxt 5 从 Vite 7 升级到 Vite 8,其中用 Rolldown 替换了 esbuild 和 Rollup 作为底层打包器。这带来显著更快的构建速度,但包含若干破坏性更改。

与 Vite 环境 API 迁移不同,此更改无法通过设置 future.compatibilityVersion: 5 提前启用。如果想提前测试 Vite 8 兼容性,可在 package.json 中添加 "vite": "^8.0.0-beta.15" 的依赖覆盖。

大多数迁移由 Nuxt 内部处理,但有些面向用户的变化需要关注:

  • vite.esbuildvite.optimizeDeps.esbuildOptions 已弃用,替换为 vite.oxcvite.optimizeDeps.rolldownOptions。Vite 8 目前自动转换这些选项,但未来将移除旧选项。
  • build.rollupOptions 弃用,改用 build.rolldownOptions
  • CommonJS 互操作行为改变。如果使用 CJS 模块,请查阅 Vite 8 迁移指南
查看完整 Vite 8 迁移指南及破坏性更改

迁移到 Nitro v3

🚦 影响级别:重大

发生了什么变化

Nuxt 5 升级到了 Nitro v3,这是服务器引擎的一次重大重写。Nitro v3 基于 srvxh3 v2 构建,全面采用 Web 标准的 Request/Response API。这带来了性能提升和更一致的 API,但服务器端代码存在若干破坏性变更。

我们仍在继续完善 Nitro v3 集成,因此你应预期会有更多变化,以及额外工作来让迁移更加顺利。
阅读 Nitro v3 测试版公告以获取完整概览。
查看完整的 Nitro v3 迁移指南以了解所有破坏性变更。

以下章节重点介绍对 Nuxt 应用开发者和模块作者最相关的变化。

包及导入路径变化

nitropack 包更名为 nitro。所有导入路径都发生了变化:

之前之后
nitropacknitro
nitropack/typesnitro/types
nitropack/runtimenitro
h3 (for server utilities)nitro/h3

服务器路由内的自动导入(如 defineEventHandlergetQueryreadBodyuseRuntimeConfig 等)继续可用且无需更改。

如果代码中有显式导入,需要更新:

- import { defineEventHandler, getQuery } from 'h3'
+ import { defineEventHandler, getQuery } from 'nitro/h3'

模块作者注意,类型扩展必须针对新的模块路径:

- declare module 'nitropack/types' {
+ declare module 'nitro/types' {
    interface NitroRouteRules {
      myModule?: { /* ... */ }
    }
  }

错误处理:status/statusText 替代 statusCode/statusMessage

h3 v2 重命名了错误属性以符合 Web 标准:

  createError({
-   statusCode: 404,
-   statusMessage: 'Not Found',
+   status: 404,
+   statusText: 'Not Found',
  })

在服务器路由中,错误类由 createError 变为 HTTPError

- import { createError } from 'h3'
+ import { HTTPError } from 'nitro/h3'

  export default defineEventHandler(() => {
-   throw createError({ statusCode: 400, statusMessage: 'Bad request' })
+   throw new HTTPError({ status: 400, statusText: 'Bad request' })
  })
在应用的 Vue 部分(app/ 目录),Nuxt 的 createError 组合式函数依旧可用,并且推荐用于抛出错误。

服务器事件 API 变化(h3 v2)

H3Event 对象现采用 Web 标准 API:

请求属性:

- event.path              // 字符串
+ event.url.pathname      // URL 对象 - 使用 .pathname,.search,.hash

- event.method            // 字符串
+ event.req.method        // 通过 Web Request 对象

- event.node.req.headers  // Node.js IncomingHttpHeaders
+ event.req.headers       // Web Headers API(.get()、.set()、.has())

响应属性:

- event.node.res.statusCode = 200
+ event.res.status = 200

- event.node.res.statusMessage = 'OK'
+ event.res.statusText = 'OK'

- setResponseHeader(event, 'x-custom', 'value')
+ event.res.headers.set('x-custom', 'value')

- appendResponseHeader(event, 'set-cookie', cookie)
+ event.res.headers.append('set-cookie', cookie)

useRuntimeConfig() 不再接受 event

在 Nitro v3 中,useRuntimeConfig() 在服务器路由中不再需要(也不接受)传入 event 参数:

  export default defineEventHandler((event) => {
-   const config = useRuntimeConfig(event)
+   const config = useRuntimeConfig()
  })

路由规则:statusCode 重命名为 status

如果定义了重定向路由规则,属性名称发生了变化:

  export default defineNuxtConfig({
    routeRules: {
      '/old-page': {
-       redirect: { to: '/new-page', statusCode: 302 },
+       redirect: { to: '/new-page', status: 302 },
      },
    },
  })

模块作者的其他变化

  • Nitro 插件导入:使用 import { definePlugin } from 'nitro' 进行显式导入(自动导入仍然有效)。
  • 运行时钩子nitroApp.hooks.hook('beforeResponse', ...)nitroApp.hooks.hook('afterResponse', ...) 已被 nitroApp.hooks.hook('response', ...) 替代。
  • getRouteRules() from nitro/app:在服务器上,Nitro 辅助函数从 getRouteRules(event) 更改为 getRouteRules(method, pathname),返回 { routeRules }

移除 experimental.externalVue

🚦 影响级别:极小

变化内容

experimental.externalVue 选项已被移除。当未启用 vue.runtimeCompiler 时,Vue 编译器依赖(@babel/parser@vue/compiler-core@vue/compiler-dom@vue/compiler-ssrestree-walker)现在始终在服务器包中被替换为模拟代理。

变更原因

随着迁移到 Nitro v3,所有依赖项默认都会打包到服务器输出中(不像 Nitro v2 那样将 node_modules 外部化)。externalVue 选项最初设计用于将 Vue 保持为外部依赖,这是为了避免打包多个 Vue 副本,但由于 Nitro v3 无论如何都会打包所有内容,该选项变得无效。

Vue 的服务器构建包含完整的编译器工具链,会不必要地将 @babel/parser(465KB)和其他编译器包拉入服务器包中。这些编译器包仅在启用 vue.runtimeCompiler 进行运行时模板编译时才需要。

通过始终模拟这些编译器依赖,默认服务器包大小减少了约 860KB(约 59%)。

迁移步骤

如果你之前显式设置了 experimental.externalVue,现在应该将其移除。

  export default defineNuxtConfig({
    experimental: {
-     externalVue: false,
    },
  })
如果你使用 vue.runtimeCompiler: true,真正的编译器包仍会像以前一样包含在内。

@vitejs/plugin-vue-jsx 现为可选

🚦 影响级别:极小

变化内容

@vitejs/plugin-vue-jsx 不再随 @nuxt/vite-builder 默认安装。它现在是可选的对等依赖,仅在构建过程中遇到 .jsx.tsx 文件时按需加载。

如果你的项目使用 JSX/TSX 组件,Nuxt 将自动检测并提示你安装该包。

变更原因

@vitejs/plugin-vue-jsx 插件会引入大量依赖树(Babel、@vue/babel-plugin-jsx 等),对于不使用 JSX 的项目来说是不必要的。将其设为可选可减少默认安装大小并加快大多数 Nuxt 项目的依赖解析速度。

迁移步骤

如果你的项目使用 .jsx.tsx 文件,请将 @vitejs/plugin-vue-jsx 添加为开发依赖:

npm install -D @vitejs/plugin-vue-jsx

或者,Nuxt 将在开发期间首次处理 JSX/TSX 文件时自动提示你安装。

如果你的项目不使用 JSX,则无需更改。

移除旧版 _renderResponse 支持

🚦 影响级别:极小

发生了什么变化

不再支持对 ssrContext._renderResponse 的兼容回退检测。现在仅使用 Nuxt 导航组合函数设置的内部 ssrContext['~renderResponse']

变更原因

ssrContext 上的 _renderResponse 属性在内部 API 迁移到 ~renderResponse(见 #33896)后,仅作为兼容回退保留。TODO 注释指出应在 Nuxt v5 中移除。

迁移步骤

如果你之前直接设置过 ssrContext._renderResponse(这从未是公开 API),请改用 ssrContext['~renderResponse']。Nuxt 导航组合函数已使用新属性,因此如果你使用 navigateTo 或路由中间件,则无需更改。

非异步 callHook

🚦 影响级别:极小

变化内容

升级到 hookable v6 后,callHook 现在可能返回 void,而非一直返回 Promise<void>。这是一项性能改进,可在没有钩子或仅有同步钩子的情况下避免不必要的 Promise 分配。

默认情况下(兼容版本为 4),Nuxt 使用 Promise.resolve() 包装 callHook,以确保现有的 .then().catch() 链式调用正常工作。设置兼容版本为 5 时,将移除此包装。

此变动影响构建时的 Nuxt 钩子(模块使用)和运行时的钩子(应用代码中使用)。

变更原因

Hookable v6 避免不必要的 Promise 创建,使钩子调用速度提高 20–40 倍,利于有大量钩子的应用。

迁移步骤

如果你(或你使用的模块)在 callHook 上使用 .then().catch(),请改用 await

- nuxtApp.callHook('my:hook', data).then(() => { ... })
+ await nuxtApp.callHook('my:hook', data)
- nuxtApp.hooks.callHook('my:hook', data).catch(err => { ... })
+ try { await nuxtApp.hooks.callHook('my:hook', data) } catch (err) { ... }
你可以通过设置 future.compatibilityVersion: 5(参见测试 Nuxt 5)或显式启用 experimental.asyncCallHook: false 来提前测试此功能。

或者,确保 callHook 始终返回 Promise:

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

客户端专属注释占位符

🚦 影响级别:极小

变化内容

使用 compatibilityVersion: 5 时,客户端专属组件(.client.vue 文件和 createClientOnly() 包装器)现在在服务器上渲染 HTML 注释(<!--placeholder-->)而非空 <div> 元素。

  • nuxt.config.tsmodules 数组中定义的模块
  • modules/ 目录中自动发现的模块

当占位符 <div> 与实际组件根元素共享相同标签名时,Vue 运行时在激活期间会跳过重新应用 setScopeId。这会导致组件挂载后作用域样式丢失。使用注释节点可完全避免标签名冲突。

此改动确保:

如果你依赖占位符 <div> 来继承属性(classstyle 等)以用于布局(例如,预留空间防止布局偏移),请将组件包装在 <ClientOnly> 中并添加 #fallback 插槽:

- <MyComponent class="placeholder" style="min-height: 200px" />
+ <ClientOnly>
+   <MyComponent />
+   <template #fallback>
+     <div class="placeholder" style="min-height: 200px"></div>
+   </template>
+ </ClientOnly>
你可以通过设置 future.compatibilityVersion: 5(参见测试 Nuxt 5)或显式启用 experimental.clientNodePlaceholder: true 来提前测试此功能。

或者,你可以通过以下配置恢复之前的 <div> 占位符行为:

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