Vite 5.0有哪些新变化?

2023-11-22 10:24:20 浏览数 (2)

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项目中,需要确保:

  1. 文件vite.config.js内容使用ESM语法。
  2. 最接近的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 中。
  • 在构建时,这两个特性都使用正则表达式进行静态替换。

这导致在尝试访问这些变量时,开发和构建存在一致性问题,有时甚至导致构建失败。例如:

代码语言:javascript复制
// vite.config.js
export default defineConfig({
  define: {
    __APP_VERSION__: JSON.stringify('1.0.0'),
  },
})
代码语言:javascript复制
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 处理,以匹配生产环境行为。在实践中,这不应影响正确打包的依赖项,但是如果你在加载模块时遇到新的问题,你可以尝试以下重构:

代码语言:javascript复制
// 之前:
import { foo } from 'bar'

// 之后:
import _bar from 'bar'
const { foo } = _bar
代码语言:javascript复制
// 之前:
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 重构成了一个单一的行为,如下所示,给定以下文件结构:

代码语言:javascript复制
├── 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 库。

代码语言:javascript复制
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)

扩展链接

新手入门-在Vue框架中嵌入前端Excel表格插件(上)

VUE 3 组件开发实战 – 在线电子表格文档编辑(一)

0 人点赞