Skip to content

Commit

Permalink
Merge pull request #954 from vitejs/dev
Browse files Browse the repository at this point in the history
Release for Vite v5.2.11
  • Loading branch information
waynzh authored May 10, 2024
2 parents b71595f + 013f1fa commit 77a24b9
Show file tree
Hide file tree
Showing 16 changed files with 738 additions and 247 deletions.
4 changes: 4 additions & 0 deletions .vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ export default defineConfig({
{ text: 'Releases', link: '/releases' },
{
items: [
{
text: 'Mastodon',
link: 'https://elk.zone/m.webtoo.ls/@vite',
},
{
text: 'Twitter',
link: 'https://twitter.com/vite_js',
Expand Down
2 changes: 1 addition & 1 deletion config/dep-optimization-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

默认情况下,Vite 会抓取你的 `index.html` 来检测需要预构建的依赖项(忽略了`node_modules``build.outDir``__tests__``coverage`)。如果指定了 `build.rollupOptions.input`,Vite 将转而去抓取这些入口点。

如果这两者都不合你意,则可以使用此选项指定自定义条目——该值需要遵循 [fast-glob 模式](https://github.com/mrmlnc/fast-glob#basic-syntax) ,或者是相对于 Vite 项目根目录的匹配模式数组。当显式声明了 `optimizeDeps.entries` 时默认只有 `node_modules``build.outDir` 文件夹会被忽略。如果还需忽略其他文件夹,你可以在模式列表中使用以 `!` 为前缀的、用来匹配忽略项的模式。
如果这两者都不合你意,则可以使用此选项指定自定义条目——该值需要遵循 [fast-glob 模式](https://github.com/mrmlnc/fast-glob#basic-syntax) ,或者是相对于 Vite 项目根目录的匹配模式数组。当显式声明了 `optimizeDeps.entries` 时默认只有 `node_modules``build.outDir` 文件夹会被忽略。如果还需忽略其他文件夹,你可以在模式列表中使用以 `!` 为前缀的、用来匹配忽略项的模式。如果你不想忽略 `node_modules``build.outDir`,你可以选择直接使用字符串路径(不使用 fast-glob 模式)。

## optimizeDeps.exclude {#optimizedeps-exclude}

Expand Down
4 changes: 4 additions & 0 deletions config/shared-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ export default defineConfig({

该选项用于选择用于 CSS 处理的引擎。详细信息请查看 [Lightning CSS](../guide/features.md#lightning-css)

::: info 重复的 `@import`
需要注意的是,postcss(postcss-import)处理重复 `@import` 的行为与浏览器是不同的。详情请参考 [postcss/postcss-import#462](https://github.com/postcss/postcss-import/issues/462)
:::

## css.lightningcss

- **实验性:** [提供反馈](https://github.com/vitejs/vite/discussions/13835)
Expand Down
2 changes: 1 addition & 1 deletion guide/api-hmr.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ import.meta.hot.accept((module) => {
如果在连接前调用,数据会先被缓存、等到连接建立好后再发送。
查看 [客户端与服务器的数据交互](/guide/api-plugin.html#client-server-communication) 一节获取更多细节
查看 [客户端与服务端间通信](/guide/api-plugin.html#client-server-communication) 以及 [自定义事件的 TypeScript 类型定义指南](/guide/api-plugin.html#typescript-for-custom-events) 章节获取更多细节
## 推荐阅读 {#further-reading}
Expand Down
32 changes: 29 additions & 3 deletions guide/api-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,8 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
- 带有 `enforce: 'post'` 的用户插件
- Vite 后置构建插件(最小化,manifest,报告)

请注意,这与钩子的排序是分开的,钩子的顺序仍然会受到它们的 `order` 属性的影响,这一点 [和 Rollup 钩子的表现一样](https://rollupjs.org/plugin-development/#build-hooks)。

## 情景应用 {#conditional-application}

默认情况下插件在开发(serve)和构建(build)模式中都会调用。如果插件只需要在预览或构建期间有条件地应用,请使用 `apply` 属性指明它们仅在 `'build'``'serve'` 模式时调用:
Expand Down Expand Up @@ -622,16 +624,40 @@ export default defineConfig({

### 自定义事件的 TypeScript 类型定义指南 {#typeScript-for-custom-events}

可以通过扩展 `CustomEventMap` 这个 interface 来为自定义事件标注类型:
Vite 会在内部从 `CustomEventMap` 这个接口推断出 payload 的类型,可以通过扩展这个接口来为自定义事件进行类型定义:

:::tip 提示
在指定 TypeScript 声明文件时,确保包含 `.d.ts` 扩展名。否则,TypeScript 可能不会知道试图扩展的是哪个文件。
:::

```ts
// events.d.ts
import 'vite/types/customEvent'
import 'vite/types/customEvent.d.ts'
declare module 'vite/types/customEvent' {
declare module 'vite/types/customEvent.d.ts' {
interface CustomEventMap {
'custom:foo': { msg: string }
// 'event-key': payload
}
}
```

这个接口扩展被 `InferCustomEventPayload<T>` 所使用,用来推断事件 `T` 的 payload 类型。要了解更多关于这个接口如何被使用的信息,请参考 [HMR API 文档](./api-hmr#hmr-api)。

```ts twoslash
import 'vite/client'
import type { InferCustomEventPayload } from 'vite/types/customEvent.d.ts'
declare module 'vite/types/customEvent.d.ts' {
interface CustomEventMap {
'custom:foo': { msg: string }
}
}
// ---cut---
type CustomFooPayload = InferCustomEventPayload<'custom:foo'>
import.meta.hot?.on('custom:foo', (payload) => {
// payload 的类型为 { msg: string }
})
import.meta.hot?.on('unknown:event', (payload) => {
// payload 的类型为 any
})
```
6 changes: 4 additions & 2 deletions guide/api-vite-runtime.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Vite 运行时 API {#vite-runtime-api}

:::warning 低级别 API
这个 API 在 Vite 5.1 中作为一个实验性特性引入。它被添加以 [收集反馈](https://github.com/vitejs/vite/discussions/15774)。在Vite 5.2 中,它可能会有破坏性的变化,所以在使用它时,请确保将 Vite 版本固定在 `~5.1.0`。这是一个面向库和框架作者的低级别 API。如果你的目标是开发应用,请确保首先查看 [Vite SSR 精选板块](https://github.com/vitejs/awesome-vite#ssr) 的高级 SSR 插件和工具。
:::warning 底层 API
这个 API 在 Vite 5.1 中作为一个实验性特性引入。它被添加以 [收集反馈](https://github.com/vitejs/vite/discussions/15774)。在Vite 5.2 中,它可能会有破坏性的变化,所以在使用它时,请确保将 Vite 版本固定在 `~5.1.0`。这是一个面向库和框架作者的底层 API。如果你的目标是开发应用,请确保首先查看 [Vite SSR 精选板块](https://github.com/vitejs/awesome-vite#ssr) 的高级 SSR 插件和工具。

目前,这种 API 正在以 [环境 API](https://github.com/vitejs/vite/discussions/16358) 的形式进行修正,并在 `^6.0.0-alpha.0` 版本中发布。
:::

"Vite 运行时" 是一个工具,它允许首先用 Vite 插件处理任何代码后运行。它与 `server.ssrLoadModule` 不同,因为运行时实现是从服务器解耦的。这允许库和框架作者实现他们自己的服务器和运行时之间的通信层。
Expand Down
68 changes: 40 additions & 28 deletions guide/backend-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,36 @@

```json
{
"main.js": {
"file": "assets/main.4889e940.js",
"src": "main.js",
"_shared-!~{003}~.js": {
"file": "assets/shared-ChJ_j-JJ.css",
"src": "_shared-!~{003}~.js"
},
"_shared-B7PI925R.js": {
"file": "assets/shared-B7PI925R.js",
"name": "shared",
"css": ["assets/shared-ChJ_j-JJ.css"]
},
"baz.js": {
"file": "assets/baz-B2H3sXNv.js",
"name": "baz",
"src": "baz.js",
"isDynamicEntry": true
},
"views/bar.js": {
"file": "assets/bar-gkvgaI9m.js",
"name": "bar",
"src": "views/bar.js",
"isEntry": true,
"dynamicImports": ["views/foo.js"],
"css": ["assets/main.b82dbe22.css"],
"assets": ["assets/asset.0ab0f9cd.png"],
"imports": ["_shared.83069a53.js"]
"imports": ["_shared-B7PI925R.js"],
"dynamicImports": ["baz.js"]
},
"views/foo.js": {
"file": "assets/foo.869aea0d.js",
"file": "assets/foo-BRBmoGS9.js",
"name": "foo",
"src": "views/foo.js",
"isDynamicEntry": true,
"imports": ["_shared.83069a53.js"]
},
"_shared.83069a53.js": {
"file": "assets/shared.83069a53.js",
"css": ["assets/shared.a834bfc3.css"]
"isEntry": true,
"imports": ["_shared-B7PI925R.js"],
"css": ["assets/foo-5UjPuW-k.css"]
}
}
```
Expand Down Expand Up @@ -108,35 +120,35 @@
<script type="module" src="/{{ manifest[name].file }}"></script>

<!-- 对于 importedChunks(manifest, name) 中的 chunk -->
<link rel="modulepreload" src="/{{ chunk.file }}" />
<link rel="modulepreload" href="/{{ chunk.file }}" />
```

具体来说,一个生成 HTML 的后端在给定 manifest 文件和一个入口文件的情况下,
应该包含以下标签:

- 对于入口文件 chunk 的 `css` 列表中的每个文件,都应包含一个 `<link rel="stylesheet">` 标签。
- 递归追踪入口文件的 `imports` 列表中的所有 chunk,并为每个导入的 chunk 的每个 css 文件
- 递归追踪入口文件的 `imports` 列表中的所有 chunk,并为每个导入的 chunk 的每个 CSS 文件
包含一个 `<link rel="stylesheet">` 标签。
- 对于入口文件 chunk 的 `file` 键的标签(对于 Javascript 是
`<script type="moudle">`,对于 css`<link rel="stylesheet">`
- 可选项,对于每个导入的 Javascript chunk 的 `file` 键的 `<link rel="modulepreload">` 标签,
- 对于入口文件 chunk 的 `file` 键的标签(对于 JavaScript 是
`<script type="module">`,对于 CSS`<link rel="stylesheet">`
- 可选项,对于每个导入的 JavaScript chunk 的 `file` 键的 `<link rel="modulepreload">` 标签,
同样从入口文件 chunk 开始递归追踪导入。

按照上面的示例 manifest,对于入口文件 `main.js`,在生产环境中应包含以下标签:
按照上面的示例 manifest,对于入口文件 `views/foo.js`,在生产环境中应包含以下标签:

```html
<link rel="stylesheet" href="assets/main.b82dbe22.css" />
<link rel="stylesheet" href="assets/shared.a834bfc3.css" />
<script type="module" src="assets/main.4889e940.js"></script>
<link rel="stylesheet" href="assets/foo-5UjPuW-k.css" />
<link rel="stylesheet" href="assets/shared-ChJ_j-JJ.css" />
<script type="module" src="assets/foo-BRBmoGS9.js"></script>
<!-- 可选 -->
<link rel="modulepreload" src="assets/shared.83069a53.js" />
<link rel="modulepreload" href="assets/shared-B7PI925R.js" />
```

而对于入口文件 `views/foo.js`,应该包含以下标签:
而对于入口文件 `views/bar.js`,应该包含以下标签:

```html
<link rel="stylesheet" href="assets/shared.a834bfc3.css" />
<script type="module" src="assets/foo.869aea0d.js"></script>
<link rel="stylesheet" href="assets/shared-ChJ_j-JJ.css" />
<script type="module" src="assets/bar-gkvgaI9m.js"></script>
<!-- 可选 -->
<link rel="modulepreload" src="assets/shared.83069a53.js" />
<link rel="modulepreload" href="assets/shared-B7PI925R.js" />
```
42 changes: 15 additions & 27 deletions guide/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,7 @@ export default defineConfig({

## 产物分块策略 {#chunking-strategy}

你可以通过配置 `build.rollupOptions.output.manualChunks` 来自定义 chunk 分割策略(查看 [Rollup 相应文档](https://rollupjs.org/configuration-options/#output-manualchunks))。在 Vite 2.8 及更早版本中,默认的策略是将 chunk 分割为 `index``vendor`。这对一些 SPA 来说是好的策略,但是要对所有应用场景提供一种通用解决方案是非常困难的。从 Vite 2.9 起,`manualChunks` 默认情况下不再被更改。你可以通过在配置文件中添加 `splitVendorChunkPlugin` 来继续使用 “分割 Vendor Chunk” 策略:

```js
// vite.config.js
import { splitVendorChunkPlugin } from 'vite'
export default defineConfig({
plugins: [splitVendorChunkPlugin()],
})
```

也可以用一个工厂函数 `splitVendorChunk({ cache: SplitVendorChunkCache })` 来提供该策略,在需要与自定义逻辑组合的情况下,`cache.reset()` 需要在 `buildStart` 阶段被调用,以便构建的 watch 模式在这种情况下正常工作。

::: warning
你应该使用 `build.rollupOptions.output.manualChunks` 函数形式来使用此插件。如果使用对象形式,插件将不会生效。
:::
你可以通过配置 `build.rollupOptions.output.manualChunks` 来自定义 chunk 分割策略(查看 [Rollup 相应文档](https://cn.rollupjs.org/configuration-options/#output-manualchunks))。如果你使用的是一个框架,那么请参考他们的文档来了解如何配置分割 chunk。

## 处理加载报错 {#load-error-handling}

Expand Down Expand Up @@ -271,24 +257,26 @@ experimental: {

如果 hash 后的资源和公共文件没有被部署在一起,可以根据该函数的第二个参数 `context` 上的字段 `type` 分别定义各个资源组的选项:

<!-- prettier-ignore-start -->
```ts twoslash
import type { UserConfig } from 'vite'
import path from 'node:path'
const config: UserConfig = {
// ---cut-before---
experimental: {
renderBuiltUrl(filename, { hostId, hostType, type }) {
if (type === 'public') {
return 'https://www.domain.com/' + filename
} else if (path.extname(hostId) === '.js') {
return { runtime: `window.__assetsPath(${JSON.stringify(filename)})` }
} else {
return 'https://cdn.domain.com/assets/' + filename
}
},
// ---cut-before---
experimental: {
renderBuiltUrl(filename, { hostId, hostType, type }) {
if (type === 'public') {
return 'https://www.domain.com/' + filename
} else if (path.extname(hostId) === '.js') {
return { runtime: `window.__assetsPath(${JSON.stringify(filename)})` }
} else {
return 'https://cdn.domain.com/assets/' + filename
}
},
// ---cut-after---
},
// ---cut-after---
}
```
<!-- prettier-ignore-end -->

请注意,传递的 `filename` 是一个已解码的 URL,如果函数返回了一个 URL 字符串,那么它也应该是已解码的。当 Vite 渲染 URL 时会自动处理编码。如果返回的是一个带有 `runtime` 的对象,就需要在必要的地方自行处理编码,因为运行时的代码将会按照原样呈现。
2 changes: 1 addition & 1 deletion guide/env-and-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 环境变量 {#env-variables}

Vite 在一个特殊的 **`import.meta.env`** 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量:
Vite 在一个特殊的 **`import.meta.env`** 对象上暴露环境变量,这些变量在构建时会被静态地替换掉。这里有一些在所有情况下都可以使用的内建变量:

- **`import.meta.env.MODE`**: {string} 应用运行的[模式](#modes)

Expand Down
2 changes: 1 addition & 1 deletion guide/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ import MyWorker from './worker?worker&url'

### [`'nonce-{RANDOM}'`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/Sources#nonce-base64-value)

当设置了 [`html.cspNonce`](/config/shared-options#html-cspnonce) 时,Vite 会在输出的脚本标签和样式表的链接标签中添加一个带有指定值的 nonce 属性。请注意,Vite 不会将 nonce 属性添加到其他标签中,例如 `<style>`。此外,设置此选项时,Vite 将注入一个 meta 标签`<meta property="csp-nonce" nonce="PLACEHOLDER" />`
当设置了 [`html.cspNonce`](/config/shared-options#html-cspnonce) 时,Vite 会为任何 `<script>``<style>` 标签,以及样式表和模块预加载的 `<link>` 标签添加一个 nonce 属性。此外,当设置了这个选项时,Vite 会注入一个 meta 标签 (`<meta property="csp-nonce" nonce="PLACEHOLDER" />`)

带有 `property="csp-nonce"` 的 meta 标签的 nonce 值将在开发和构建后的必要时刻被 Vite 使用。

Expand Down
17 changes: 6 additions & 11 deletions guide/ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ SSR 特别指支持在 Node.js 中运行相同应用程序的前端框架(例
下面的指南还假定你在选择的框架中有使用 SSR 的经验,并且只关注特定于 Vite 的集成细节。
:::

:::warning Low-level API
:::warning 底层 API
这是一个底层 API,是为库和框架作者准备的。如果你的目标是构建一个应用程序,请确保优先查看 [Vite SSR 章节](https://github.com/vitejs/awesome-vite#ssr) 中更上层的 SSR 插件和工具。也就是说,大部分应用都是基于 Vite 的底层 API 之上构建的。

目前,Vite 正在用 [环境 API](https://github.com/vitejs/vite/discussions/16358) 来改进 SSR API。查看链接了解更多详情。
:::

:::tip 帮助
Expand Down Expand Up @@ -138,17 +140,10 @@ app.use('*', async (req, res, next) => {
// 例如:@vitejs/plugin-react 中的 global preambles
template = await vite.transformIndexHtml(url, template)

// 3a. 加载服务器入口。vite.ssrLoadModule 将自动转换
// 3. 加载服务器入口。vite.ssrLoadModule 将自动转换
// 你的 ESM 源码使之可以在 Node.js 中运行!无需打包
// 并提供类似 HMR 的根据情况随时失效。
const { render } = await vite.ssrLoadModule('/src/entry-server.js')
// 3b. 从 Vite 5.1 版本开始,你可以试用实验性的 createViteRuntime
// API。
// 这个 API 完全支持热更新(HMR),其工作原理与 ssrLoadModule 相似
// 如果你想尝试更高级的用法,可以考虑在另一个线程,甚至是在另一台机器上,
// 使用 ViteRuntime 类来创建运行环境。
const runtime = await vite.createViteRuntime(server)
const { render } = await runtime.executeEntrypoint('/src/entry-server.js')

// 4. 渲染应用的 HTML。这假设 entry-server.js 导出的 `render`
// 函数调用了适当的 SSR 框架 API。
Expand Down Expand Up @@ -183,7 +178,7 @@ app.use('*', async (req, res, next) => {
为了将 SSR 项目交付生产,我们需要:
1. 正常生成一个客户端构建;
2. 再生成一个 SSR 构建,使其通过 `import()` 直接加载,这样便无需再使用 Vite 的 `ssrLoadModule``runtime.executeEntrypoint`
2. 再生成一个 SSR 构建,使其通过 `import()` 直接加载,这样便无需再使用 Vite 的 `ssrLoadModule`
`package.json` 中的脚本应该看起来像这样:
Expand All @@ -203,7 +198,7 @@ app.use('*', async (req, res, next) => {
- 使用 `dist/client/index.html` 作为模板,而不是根目录的 `index.html`,因为前者包含了到客户端构建的正确资源链接。
- 使用 `import('./dist/server/entry-server.js')` (该文件是 SSR 构建产物),而不是使用 `await vite.ssrLoadModule('/src/entry-server.js')``await runtime.executeEntrypoint('/src/entry-server.js')`
- 使用 `import('./dist/server/entry-server.js')` (该文件是 SSR 构建产物),而不是使用 `await vite.ssrLoadModule('/src/entry-server.js')`
- 将 `vite` 开发服务器的创建和所有使用都移到 dev-only 条件分支后面,然后添加静态文件服务中间件来服务 `dist/client` 中的文件。
Expand Down
Loading

0 comments on commit 77a24b9

Please sign in to comment.