Rollup 4
Vite 现在使用 Rollup 4,它也带来了一些重大的变化,特别是:
- 导入断言(assertions 属性)已被重命名为导入属性(attributes 属性)。
- 不再支持 Acorn 插件。
- 对于 Vite 插件,this.resolve 的 skipSelf 选项现在默认为 true。
- 对于 Vite 插件,this.parse 现在只支持 allowReturnOutsideFunction 选项。
你可以阅读 Rollup 的发布说明 中的破坏性变更,了解在 build.rollupOptions 中构建相关的变更。
如果你正在使用 TypeScript,请确保将 moduleResolution: 'bundler'(或 node16/nodenext)设置为 Rollup 4 需要它。或者你可以设置 skipLibCheck: true。
弃用CJS节点API
Vite 的 CJS Node API 已弃用。调用 时require('vite'),现在会记录弃用警告。应该更新文件或框架以导入 Vite 的 ESM 版本。
在一个基础的Vite项目中,需要确保:
- 文件vite.config.js内容使用ESM语法。
- 最接近的package.json文件具有"type": "module",或使用.mjs/.mts扩展名,例如vite.config.mjs或vite.config.mts。
对于其他项目,有一些通用方法:
- 将 ESM 配置为默认值,如果需要,选择加入 CJS:添加"type": "module"到项目中package.json。所有*.js文件现在都解释为 ESM,并且需要使用 ESM 语法。您可以使用扩展名重命名文件.cjs以继续使用 CJS。
- 将 CJS 保留为默认值,如果需要,选择加入 ESM:如果项目package.json没有"type": "module",则所有*.js文件都将解释为 CJS。您可以使用扩展名重命名文件.mjs以改用 ESM。
- 动态导入Vite:如果需要继续使用CJS,可以import('vite')改为使用动态导入Vite。这要求您的代码是在async上下文中编写的,但仍应易于管理,因为 Vite 的 API 大部分是异步的。
重新设计 define 和 import.meta.env.* 的替换策略
在Vite 4 中,define 和 import.meta.env.* 特性在开发和构建中使用的是不同的替换策略:
- 在开发时,这两个特性分别作为全局变量注入到 globalThis 和 import.meta 中。
- 在构建时,这两个特性都使用正则表达式进行静态替换。
这导致在尝试访问这些变量时,开发和构建存在一致性问题,有时甚至导致构建失败。例如:
// vite.config.js
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify('1.0.0'),
},
})
const data = { __APP_VERSION__ }
// 开发:{ __APP_VERSION__: "1.0.0" } ✅
// 构建:{ "1.0.0" } ❌
const docs = 'I like import.meta.env.MODE'
// 开发:"I like import.meta.env.MODE" ✅
// 构建:"I like "production"" ❌
Vite 5 通过在构建中使用 esbuild 来处理替换,使其与开发行为保持一致。
SSR 外部模块值现在符合生产环境行为
在 Vite 4 中,服务器端渲染的外部模块被包装为 .default 和 .__esModule 处理,以实现更好的互操作性,但是它并不符合运行时环境(例如 Node.js)加载时的生产环境行为,导致难以捕获的不一致性。默认情况下,所有直接的项目依赖都是 SSR 外部化的。
Vite 5 现在删除了 .default 和 .__esModule 处理,以匹配生产环境行为。在实践中,这不应影响正确打包的依赖项,但是如果你在加载模块时遇到新的问题,你可以尝试以下重构:
// 之前:
import { foo } from 'bar'
// 之后:
import _bar from 'bar'
const { foo } = _bar
// 之前:
import foo from 'bar'
// 之后:
import * as _foo from 'bar'
const foo = _foo.default
注意,这些更改符合 Node.js 的行为,因此也可以在 Node.js 中运行这些导入进行测试。如果更喜欢坚持使用之前的方式,也可以将 legacy.proxySsrExternalModules 设置为 true。
worker.plugins 现在是一个函数
在 Vite 4 中,worker.plugins 接受一个插件数组 ((Plugin | Plugin[])[])。从 Vite 5 开始,它需要配置为一个返回插件数组的函数 (() => (Plugin | Plugin[])[])。这个改变是为了让并行的 worker 构建运行得更加一致和可预测。
允许路径包含 . 回退到 index.html
在 Vite 4 中,即使 appType 被设置为 'SPA'(默认),访问包含 . 的路径也不会回退到 index.html。从 Vite 5 开始,它将会回退到 index.html。
调整开发和预览 HTML 服务行为
在 Vite 4 中,开发服务器和预览服务器会根据 HTML 的目录结构和尾部斜杠的不同来提供 HTML。这会导致在测试构建后的应用时出现不一致的情况。Vite 5 重构成了一个单一的行为,如下所示,给定以下文件结构:
├── index.html
├── file.html
└── dir
└── index.html
请求 | 过往版本 (dev) | 过往版本 (preview) | 现在 (dev & preview) |
---|---|---|---|
/dir/index.html | /dir/index.html | /dir/index.html | /dir/index.html |
/dir | /index.html (SPA fallback) | /dir/index.html | /index.html (SPA fallback) |
/dir/ | /dir/index.html | /dir/index.html | /dir/index.html |
/file.html | /file.html | /file.html | /file.html |
/file | /index.html (SPA fallback) | /file.html | /file.html |
/file/ | /index.html (SPA fallback) | /file.html | /index.html (SPA fallback) |
Manifest 文件现在默认生成到 .vite 目录中
在 Vite 4 中,manifest 文件(build.manifest,build.ssrManifest)默认会生成在 build.outDir 的根目录中。
从 Vite 5 开始,这些文件将默认生成在 build.outDir 中的 .vite 目录中。这个改变有助于解决当公共文件被复制到 build.outDir 时,具有相同 manifest 文件名时的冲突。
CLI 快捷功能键需要一个额外的 Enter 按键
CLI 快捷功能键,例如 r 重启开发服务器,现在需要额外的 Enter 按键来触发快捷功能。例如,r + Enter 可以重新开发服务器。
这个改动防止 Vite 吞噬和控制操作系统特定的快捷键,允许更好的兼容性,当将 Vite 开发服务器与其他进程结合使用时,并避免了之前的注意事项。
移除 --https 标志和 https: true
resolvePackageEntry 和 resolvePackageData API 已被移除,因为它们暴露了 Vite 的内部机制,并在过去阻碍了 Vite 4.3 的潜在优化。这些 API 可以被第三方包替代,例如:
-
resolvePackageEntry: import.meta.resolve 或者 import-meta-resolve 库。
-
resolvePackageData: 与上述相同,向上爬取包目录以获取根 package.json。或者使用社区的 vitefu 库。
-
import { resolve } from 'import-meta-env' import { findDepPkgJsonPath } from 'vitefu' import fs from 'node:fs' const pkg = 'my-lib' const basedir = process.cwd() // `resolvePackageEntry`: const packageEntry = resolve(pkg, basedir) // `resolvePackageData`: const packageJsonPath = findDepPkgJsonPath(pkg, basedir) const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
移除部分废弃 API
- CSS 文件的默认导出(例如 import style from './foo.css'):使用 ?inline 查询参数代替
- import.meta.globEager:使用 import.meta.glob('*', { eager: true }) 来代替
- ssr.format: 'cjs' 和 legacy.buildSsrCjsExternalHeuristics(#13816)
- server.middlewareMode: 'ssr' 和 server.middlewareMode: 'html':使用 appType + server.middlewareMode: true 来代替(#8452)