升级指南

了解如何升级到最新的 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,请定期回来查看。

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

已移除 process.* 类型增强

🚦 影响级别:最小

变更内容

Nuxt 不再为 NodeJS.Process 增强 browserclientdevservertest 属性。为兼容性保留了这些标志位的构建时定义,但 TypeScript 不会将它们视为已知属性。

请优先使用 import.meta.*。这些标志位会在构建时被替换,并且仍然支持 tree-shaking。

迁移步骤

请在你的应用代码、模块和库中替换旧的检查方式:

// 之前
// eslint-disable-next-line nuxt/prefer-import-meta
if (process.server) {
  /* ... */
}

// 之后
if (import.meta.server) {
  /* ... */
}

nuxt/prefer-import-meta ESLint 规则会标记仍在使用的 process.*

区分大小写的路由

🚦 影响等级:最小

变更内容

使用 compatibilityVersion: 5 时,页面路由会与 URL 区分大小写匹配,这与 Nitro 保持一致。例如,/About 将不再匹配 pages/about.vue

迁移步骤

更新链接,使其与对应页面路由的大小写保持一致。若要保持不区分大小写的匹配:

nuxt.config.ts
export default defineNuxtConfig({
  router: {
    options: {
      sensitive: false,
    },
  },
})

jiti 不再捆绑

🚦 影响级别:中等

变更内容

Nuxt 不再依赖 jiti。在打包器之外加载的文件(nuxt.config.tsmodules/ 中的文件以及层配置)现在由运行时本身导入。

你仍然可以使用 TypeScript 编写配置。 Nuxt 5 要求 Node 22.19 或更高版本,此时类型剥离默认开启,因此 nuxt.config.ts 和 TypeScript 模块可以原生加载。运行时不会执行、而 jiti 曾经替你处理的两件事是猜测文件扩展名,以及编译会生成代码的 TypeScript 语法。

否则,这两类问题只有在 Nuxt 加载文件时才会暴露出来。因此,现在生成的 node tsconfig 会按照运行时实际看到的方式描述环境(将 modulemoduleResolution 设置为 nodenext,并启用 erasableSyntaxOnly),TypeScript 会提前报告这两类问题。

这只适用于 nuxt.configmodules/ 和层配置。你的应用代码和 shared/ 代码会经过 Vite,并按照以往的方式解析。如果你需要之前的行为,可以覆盖配置:

nuxt.config.ts
export default defineNuxtConfig({
  typescript: {
    nodeTsConfig: {
      compilerOptions: {
        module: 'preserve',
        moduleResolution: 'bundler',
        erasableSyntaxOnly: false,
      },
    },
  },
})

变更原因

过去,Nuxt 会将 jiti 引入每个安装中,以加载少量文件,而现在运行时已经可以在没有它帮助的情况下加载其中的大多数文件。移除它可以减小默认安装的体积。

迁移步骤

1. 为相对导入添加文件扩展名。

nuxt.config.tsmodules/ 和层配置中的相对导入需要显式指定扩展名:

nuxt.config.ts
- import { myPlugin } from './build/my-plugin'
+ import { myPlugin } from './build/my-plugin.ts'

TypeScript 会将缺少扩展名报告为 TS2835。请注意,它的快速修复建议使用 ./build/my-plugin.js;应填写文件实际使用的扩展名(.ts),Node 会直接解析该扩展名。

裸包导入(import { defu } from 'defu')不受影响。

2. 使用可擦除的 TypeScript 语法。

类型注解会被擦除,但会生成运行时代码的语法则无法使用。在配置和模块文件中,将以下写法替换为:

  • enum Foo {} 替换为 const 对象
  • namespace / module 代码块替换为普通导出
  • 将构造函数参数属性(constructor(private x: string) {})替换为显式赋值
  • 实验性装饰器

TypeScript 会将这些问题报告为 TS1294

3. 如果你发布的是层或模块,请提供编译后的 JavaScript。

这一点仅适用于包。无论配置如何,运行时都拒绝从 node_modules 中的任何文件剥离类型,因此使用 TypeScript 编写的已发布入口文件无法原生加载,不论 Node 版本有多新。请在发布前编译为 JavaScript;如果你的包包含 nuxt.config,请将其输出为 nuxt.config.mjs。否则,每个使用该包的项目都必须安装 jiti

这不适用于你自己项目中的层:layers/*/nuxt.config.ts 会被原生加载。

4. 如果仍然需要 jiti,请安装它。

jiti 现在是可选的对等依赖。安装后,只要运行时无法自行加载某个文件,Nuxt 就会自动将其作为回退方案使用:

npm i -D jiti

无论使用哪个 Node 版本,nuxt.schema 文件始终需要 jiti:其中的 JSDoc 注解是通过导入时转换读取的,而不是通过导入文件本身读取的。

此外还有一项较小的变更:postcss.plugins 中指定的 PostCSS 插件现在由运行时解析,因此,仅能通过 Nuxt alias 条目解析的插件名称将不再加载。请使用包名称或路径。

迁移到 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' /* 或 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(用于服务器工具)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 组合式函数依旧可用,并且推荐用于抛出错误。

createError 不再返回 HTTPError 实例

NuxtError 现在是独立的类,而不是 h3 的 HTTPError 子类,因此,使用 Nuxt 的 createError 创建的错误不再匹配 instanceof HTTPError。其他方面均未变化:错误保留相同的属性,以相同的方式进行序列化,并且在 SSR 期间仍会映射到正确的 HTTP 响应。

如果按类缩小错误类型范围,请改用以下谓词之一:

- if (error instanceof HTTPError) {
+ if (HTTPError.isError(error)) {
    // 同时处理 `new HTTPError()` 和 Nuxt 的 `createError()`
  }
+ import { isNuxtError } from '#app'
+
+ if (isNuxtError(error)) {
+   // 将错误类型缩小为使用 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', ...) 替代。
  • nitro/app 中的 getRouteRules():在服务器上,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,真正的编译器包仍会像以前一样包含在内。

experimental.parseErrorData 不再可配置

🚦 影响级别:极小

变更内容

experimental.parseErrorData 选项已弃用,并且在 Nuxt 5 中会被强制启用。将其设置为 false 会记录一条警告,但除此之外会被忽略,因此错误页面上的 error.data 始终是你传递给 createError 的值。

compatibilityVersion: 4 下,该选项仍然有效,设置为 false 时仍会得到字符串化的 error.data,因此只有在选择使用 Nuxt 5 时,行为才会发生变化。

变更原因

当 Nuxt 渲染错误页面时,它会在内部请求 /__nuxt_error,并将错误随请求一起传递。过去,错误会被拆分到每个字段对应的查询参数中,而由于查询参数的值始终是字符串,error.data 会以字符串形式传递到页面,并且必须重新解析。parseErrorData 就是为了选择退出这一步解析而存在的。

现在,错误会作为单个经过 JSON 编码的参数发送,因此 error.data 会保留其原始结构,不再被字符串化。值的类型也会保留,因此 status 是数字,布尔值也会保持为布尔值,而不是字符串 'true''false'。由于不再有任何逻辑会将 error.data 字符串化,该选项仅为仍然期望字符串的应用保留,以便重新将其字符串化。

迁移步骤

移除该选项:

  export default defineNuxtConfig({
    experimental: {
-     parseErrorData: false,
    },
  })

如果你设置它为 false 是为了自行解析 error.data,也请移除相应的解析逻辑,因为现在 error.data 会保留你传递给 createError 的值:

  <script setup lang="ts">
  import type { NuxtError } from '#app'

  const props = defineProps({
    error: Object as () => NuxtError
  })

- const data = JSON.parse(props.error.data)
+ const data = props.error.data
  </script>

@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,则无需更改。

giget 现已成为可选依赖(远程层)

🚦 影响级别:极小

变更内容

giget 不再默认安装。现在它是 @nuxt/kit 的可选对等依赖,仅在需要下载通过远程 URL 指定的 extends 层时才需要:

nuxt.config.ts
export default defineNuxtConfig({
  extends: ['github:my-org/my-theme'],
})

本地层、位于 ~~/layers/ 中的层,以及作为软件包安装的层不受影响。

变更原因

大多数项目从不扩展远程来源,因此为所有项目安装下载器,只是为了服务少数项目。此外,在配置解析时下载层,是使用层时最不可复现的方式:获取过程发生在包管理器之外,因此不会记录在锁文件中;除非手动固定版本,否则也不会固定到某个修订版本。

迁移步骤

推荐方式:将层移入 package.json 所有主流包管理器都支持 Git URL,因此远程层可以作为普通依赖。这样它会记录在锁文件中,固定到精确的提交,并与其他依赖一起安装:

package.json
{
  "devDependencies": {
    "my-theme": "github:my-org/my-theme#4a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b"
  }
}

然后通过包名扩展它:

nuxt.config.ts
export default defineNuxtConfig({
  extends: ['my-theme'],
})

# 后面的部分可以是任意 commit-ish,因此标签(#v1.2.0)或 #semver:^1.2.0 也同样适用;只有完整的提交 SHA 才是真正不可变的形式。

否则,请安装 giget,并继续使用远程 extends 条目:

npm install -D giget

如果在未安装 giget 的情况下解析远程层,Nuxt 会报告具体哪个 extends 条目需要它。

移除旧版 _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,
  },
})

更严格的副作用导入

🚦 影响级别:最小

变更内容

compatibilityVersion: 5 下,Nuxt 生成的 tsconfig.json 会启用 noUncheckedSideEffectImports。这是 TypeScript 7 中的默认设置,因此提前采用它可以让你的项目在升级前保持一致。

启用此选项后,TypeScript 无法解析到模块的仅副作用导入(import './setup')现在会变成类型错误,而之前会被忽略。这只影响类型检查(nuxt typecheck 和你的编辑器),不影响运行时行为。

变更原因

未解析的副作用导入以前会被静默忽略,因此拼写错误或被删除的文件仍可能通过类型检查。对它们进行标记可以捕获这些错误,并与 TypeScript 7 的默认行为保持一致。

迁移步骤

如果类型检查现在对一个非代码资源的副作用导入报错(例如 import '~/assets/styles.css'),请添加一个环境模块声明,让 TypeScript 知道该导入是有效的:

types.d.ts
declare module '*.css' {}
你可以通过在 nuxt.config 中禁用该选项来恢复到之前的行为:
nuxt.config.ts
export default defineNuxtConfig({
  typescript: {
    tsConfig: {
      compilerOptions: {
        noUncheckedSideEffectImports: false,
      },
    },
  },
})
:: เครดิตฟรี

默认禁用 Vue Options API

🚦 影响级别:最小

变更内容

compatibilityVersion: 5 时,Nuxt 会将 Vue 的 __VUE_OPTIONS_API__ 特性标志设为 false,从而将 Vue 的 Options API 运行时从客户端 bundle 中编译移除。

变更原因

尽管大多数 Nuxt 应用都使用 Composition API 和 <script setup> 编写,但 Options API 运行时仍会被打包进每个客户端 bundle。移除它可以缩减客户端 bundle(在一个最小应用中约可减少 6 kB 压缩前体积 / 2 kB gzip 后体积)。

迁移步骤

如果你的任何组件(或某个依赖的组件)使用了 Options API(export default { data() {}, methods: {}, ... }),请在你的 nuxt.config 中重新启用它:
nuxt.config.ts
export default defineNuxtConfig({
  vue: {
    optionsApi: true,
  },
})
defineNuxtComponent 不受影响:它的 asyncDatahead 选项是通过 setup() 处理的,而不是通过 Vue Options API,因此无论该标志如何设置都可以正常工作。

默认启用类型化页面

🚦 影响级别:最小

变更内容

compatibilityVersion: 5 时,experimental.typedPages 会默认启用。Nuxt 会根据你的 pages/ 目录生成带类型的路由名称和路径,因此像 useRoutenavigateTo<NuxtLink>router.push 这样的组合式函数都会针对你实际的路由进行类型检查。

变更原因

类型化路由可以在类型检查阶段而不是运行时捕获失效链接和过时的路由名称,而且它现在已经成为 vue-router 的原生能力,因此作为默认设置是合理的。

迁移步骤

如果你引用了不存在的路由(例如 to 属性中的拼写错误,或者在 pages/ 目录外动态定义的路由),类型检查现在会报错。请修正该引用,或者为你在运行时添加的路由扩展生成的路由类型。

你可以通过设置 future.compatibilityVersion: 5 提前测试此功能(参见 测试 Nuxt 5),或者通过显式启用 experimental.typedPages: true 来开启它。

或者,你也可以选择退出,并通过以下方式恢复到之前的行为:

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

忽略 TypeScript baseUrl

🚦 影响级别:最小

变更内容

compatibilityVersion: 5 下,Nuxt 会从其生成的 TypeScript 配置中移除 compilerOptions.baseUrl。相对 Nuxt 和 Nitro 别名会从 Nuxt 的构建目录解析,而不是从自定义的 baseUrl 解析。

变更原因

TypeScript 6 弃用了 baseUrl,使用 paths 时也不再需要它。移除该选项还可以确保 Nuxt 生成的别名始终以包含这些别名的生成配置为基准。

迁移步骤

从 Nuxt TypeScript 配置中移除 baseUrl。如果你使用它来确定相对 Nuxt 或 Nitro 别名的基准,请改为使用绝对别名:

nuxt.config.ts
+ import { fileURLToPath } from 'node:url'
+
  export default defineNuxtConfig({
    alias: {
-     images: './assets/images',
+     images: fileURLToPath(new URL('./assets/images', import.meta.url)),
    },
-   typescript: {
-     tsConfig: {
-       compilerOptions: {
-         baseUrl: '..',
-       },
-     },
-   },
  })