功能
最基础的层面下,使用 Vite 进行开发与使用静态文件服务器没有什么不同。然而,Vite 针对原生 ESM 导入提供了许多增强功能,以支持各种在基于打包器的设置中常见的功能。
npm 依赖解析和预构建
原生 ES 导入不支持如下形式的裸模块导入:
import { someMethod } from 'my-dep'上述导入在浏览器中会报错。Vite 会检测到所有已提供源码文件中的此类裸模块导入,并执行以下操作:
预构建 (Pre-bundle):提升页面加载速度,并将 CommonJS / UMD 模块转换为 ESM。预构建步骤使用 esbuild 执行,这使得 Vite 的冷启动速度远快于任何基于 JavaScript 的打包器。
重写导入路径:将导入重写为有效的 URL,例如
/node_modules/.vite/deps/my-dep.js?v=f3sf2ebd,以便浏览器能够正确导入它们。
依赖强缓存
Vite 通过 HTTP 头缓存依赖请求,如果你想在本地编辑或调试依赖,请参考此处的步骤。
模块热替换 (HMR)
Vite 在原生 ESM 之上提供了 HMR API。具有 HMR 功能的框架可以利用该 API 提供即时、精确的更新,而无需重新加载页面或清除应用程序状态。Vite 为 Vue 单文件组件 和 React Fast Refresh 提供了第一方的 HMR 集成。此外,还有通过 @prefresh/vite 实现的 Preact 官方集成。
请注意,你不需要手动设置这些功能——当你通过 create-vite 创建应用时,所选模板已为你预先配置好了。
TypeScript
Vite 开箱即支持导入 .ts 文件。
仅转译 (Transpile Only)
请注意,Vite 仅对 .ts 文件进行转译,**不会**执行类型检查。它默认类型检查由 IDE 和构建过程处理。
Vite 不在转换过程中执行类型检查的原因是两者的工作方式存在根本差异。转译可以在单文件基础上进行,这与 Vite 的按需编译模式完美契合。相比之下,类型检查需要了解整个模块图。将类型检查强行植入 Vite 的转换管道将不可避免地牺牲 Vite 的速度优势。
Vite 的任务是尽可能快地将源模块转换为能在浏览器中运行的形式。因此,我们建议将静态分析检查与 Vite 的转换管道分离开来。这一原则同样适用于 ESLint 等其他静态分析检查。
对于生产构建,你可以在运行 Vite 构建命令的同时运行
tsc --noEmit。在开发过程中,如果你需要 IDE 提示之外的检查,我们建议在单独的进程中运行
tsc --noEmit --watch,或者如果希望在浏览器中直接看到类型错误,可以使用 vite-plugin-checker。
Vite 使用 esbuild 将 TypeScript 转译为 JavaScript,速度比原生 tsc 快约 20~30 倍,且 HMR 更新可在 50 毫秒内反映到浏览器中。
使用 仅类型导入和导出 (Type-Only Imports and Export) 语法以避免潜在问题(例如仅类型的导入被错误地打包),例如:
import type { T } from 'only/types'
export type { T }TypeScript 编译器选项
Vite 会遵守 tsconfig.json 中的部分选项,并设置相应的 esbuild 选项。对于每个文件,Vite 使用离其最近的父目录中的 tsconfig.json。如果该 tsconfig.json 包含 references 字段,Vite 将使用满足 include 和 exclude 字段的被引用配置文件。
当选项在 Vite 配置和 tsconfig.json 中同时设置时,Vite 配置中的值具有更高优先级。
tsconfig.json 中 compilerOptions 下的某些配置字段需要特别注意。
isolatedModules
应设置为 true。
这是因为 esbuild 仅执行转译且不具备类型信息,它不支持 const enum 和隐式仅类型导入等特定功能。
你必须在 tsconfig.json 的 compilerOptions 下设置 "isolatedModules": true,这样 TS 就会对那些无法在独立转译下正常工作的功能发出警告。
如果某个依赖无法很好地处理 "isolatedModules": true,你可以暂时设置 "skipLibCheck": true 来抑制错误,直到该问题在上方游得到修复。
useDefineForClassFields
如果 TypeScript 目标版本为 ES2022 或更高(包括 ESNext),其默认值将为 true。这与 TypeScript 4.3.2+ 的行为一致。其他 TypeScript 目标版本默认为 false。
true 是标准的 ECMAScript 运行时行为。
如果你使用的库严重依赖类字段(class fields),请注意该库的预期用法。虽然大多数库都期望 "useDefineForClassFields": true,但如果你的库不支持,你可以明确地将 useDefineForClassFields 设置为 false。
target
Vite 会忽略 tsconfig.json 中的 target 值,遵循与 esbuild 相同的行为。
要在开发环境中指定目标,可以使用 esbuild.target 选项,其默认值为 esnext(以进行最小化转译)。在构建时,build.target 选项的优先级高于 esbuild.target,也可以根据需要进行设置。
emitDecoratorMetadata
此选项仅得到部分支持。完全支持需要 TypeScript 编译器进行类型推断,而目前不支持。详情请参阅 Oxc Transformer 文档。
paths
可以指定 resolve.tsconfigPaths: true 来告诉 Vite 使用 tsconfig.json 中的 paths 选项来解析导入。
请注意,此功能有性能损耗,且 TypeScript 团队不建议使用此选项来改变外部工具的行为。
影响构建结果的其他编译器选项
extendsimportsNotUsedAsValuespreserveValueImportsverbatimModuleSyntaxjsxjsxFactoryjsxFragmentFactoryjsxImportSourceexperimentalDecorators
skipLibCheck
Vite 入门模板默认将 "skipLibCheck": "true" 设置为开启,以避免对依赖项进行类型检查,因为它们可能只选择支持特定的 TypeScript 版本和配置。了解更多信息请见 vuejs/vue-cli#5688。
客户端类型
Vite 的默认类型是针对其 Node.js API 的。若要为 Vite 应用中的客户端代码进行环境填充(shim),可以在 tsconfig.json 中的 compilerOptions.types 添加 vite/client。
{
"compilerOptions": {
"types": ["vite/client", "some-other-global-lib"]
}
}注意,如果指定了 compilerOptions.types,则只有这些包会被包含在全局作用域中(而不是所有可见的 ”@types” 包)。自 TS 5.9 起,推荐这样做。
使用三斜杠指令 (Triple-slash directive)
或者,你可以添加一个 d.ts 声明文件:
/// <reference types="vite/client" />vite/client 提供了以下类型填充:
提示
若要覆盖默认类型,请添加包含你自定义类型的类型定义文件,然后在 vite/client 之前添加类型引用。
例如,要将 *.svg 的默认导入改为 React 组件:
vite-env-override.d.ts(包含你类型定义的文件)tsdeclare module '*.svg' { const content: React.FC<React.SVGProps<SVGElement>> export default content }- 如果你正在使用
compilerOptions.types,请确保该文件已包含在tsconfig.json中。json{ "include": ["src", "./vite-env-override.d.ts"] } - 如果你正在使用三斜杠指令,请更新包含
vite/client引用的文件(通常是vite-env.d.ts)。ts/// <reference types="./vite-env-override.d.ts" /> /// <reference types="vite/client" />
HTML
HTML 文件在 Vite 项目中处于核心位置,作为应用程序的入口点,使得构建单页应用和多页应用变得简单。
项目根目录下的任何 HTML 文件都可以通过其对应的目录路径直接访问:
<root>/index.html->https://:5173/<root>/about.html->https://:5173/about.html<root>/blog/index.html->https://:5173/blog/index.html
由 HTML 元素(如 <script type="module" src> 和 <link href>)引用的资源会被处理并打包作为应用的一部分。以下是支持的完整元素列表:
<audio src><embed src><img src>和<img srcset><image href>和<image xlink:href><input src><link href>和<link imagesrcset><object data><script type="module" src><source src>和<source srcset><track src><use href>和<use xlink:href><video src>和<video poster><meta content>- 仅当
name属性匹配msapplication-tileimage、msapplication-square70x70logo、msapplication-square150x150logo、msapplication-wide310x150logo、msapplication-square310x310logo、msapplication-config或twitter:image时。 - 或者仅当
property属性匹配og:image、og:image:url、og:image:secure_url、og:audio、og:audio:secure_url、og:video或og:video:secure_url时。
- 仅当
<!doctype html>
<html>
<head>
<link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<img src="/src/images/logo.svg" alt="logo" />
<script type="module" src="/src/main.js"></script>
</body>
</html>要对某些元素禁用 HTML 处理,可以添加 vite-ignore 属性,这在引用外部资源或 CDN 时非常有用。
框架
所有现代框架都与 Vite 保持着集成。大多数框架插件由各自的框架团队维护,Vue 和 React 的官方 Vite 插件除外,它们由 vite 组织维护。
- Vue 支持通过 @vitejs/plugin-vue
- Vue JSX 支持通过 @vitejs/plugin-vue-jsx
- React 支持通过 @vitejs/plugin-react
- 使用 SWC 的 React 支持通过 @vitejs/plugin-react-swc
- React Server Components (RSC) 支持通过 @vitejs/plugin-rsc
查看 插件指南 以获取更多信息。
JSX
.jsx 和 .tsx 文件也开箱即支持。JSX 转译同样通过 esbuild 处理。
你所选的框架将默认配置好 JSX(例如,Vue 用户应使用官方的 @vitejs/plugin-vue-jsx 插件,它提供了 Vue 3 特定的功能,包括 HMR、全局组件解析、指令和插槽)。
如果在使用自定义框架时使用 JSX,可以使用 esbuild 选项配置自定义 jsxFactory 和 jsxFragment。例如,Preact 插件会使用:
import { defineConfig } from 'vite'
export default defineConfig({
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
})更多详情请查看 esbuild 文档。
你可以使用 jsxInject(这是一个 Vite 特有选项)注入 JSX 辅助程序,从而避免手动导入。
import { defineConfig } from 'vite'
export default defineConfig({
esbuild: {
jsxInject: `import React from 'react'`,
},
})CSS
导入 .css 文件将通过带有 HMR 支持的 <style> 标签将内容注入页面。
@import 内联与重定位
Vite 预配置了通过 postcss-import 支持 CSS @import 内联。Vite 别名在 CSS @import 中同样适用。此外,所有的 CSS url() 引用,即使导入的文件处于不同目录,也会自动重定位,以确保引用正确。
Sass 和 Less 文件也支持 @import 别名和 URL 重定位(参见 CSS 预处理器)。
PostCSS
如果项目包含有效的 PostCSS 配置(任何 postcss-load-config 支持的格式,如 postcss.config.js),它将自动应用于所有导入的 CSS。
注意,CSS 压缩将在 PostCSS 之后运行,并使用 build.cssTarget 选项。
CSS Modules
任何以 .module.css 结尾的 CSS 文件都被视为 CSS modules 文件。导入此类文件将返回对应的模块对象:
.red {
color: red;
}import classes from './example.module.css'
document.getElementById('foo').className = classes.redCSS modules 行为可以通过 css.modules 选项进行配置。
如果设置 css.modules.localsConvention 以启用 camelCase locals(例如 localsConvention: 'camelCaseOnly'),你也可以使用具名导入。
// .apply-color -> applyColor
import { applyColor } from './example.module.css'
document.getElementById('foo').className = applyColorCSS 预处理器
由于 Vite 仅针对现代浏览器,建议使用原生 CSS 变量配合实现 CSSWG 草案的 PostCSS 插件(如 postcss-nesting),并编写标准的、符合未来标准的 CSS。
尽管如此,Vite 确实提供了对 .scss、.sass、.less、.styl 和 .stylus 文件的内置支持。无需安装特定的 Vite 插件,但必须安装相应的预处理器本身:
# .scss and .sass
npm add -D sass-embedded # or sass
# .less
npm add -D less
# .styl and .stylus
npm add -D stylus如果使用 Vue 单文件组件,这也将自动启用 <style lang="sass"> 等功能。
Vite 改进了 Sass 和 Less 的 @import 解析,以便 Vite 别名也能生效。此外,导入的 Sass/Less 文件内与根文件不在同一目录的相对 url() 引用也会自动重定位,以确保准确性。由于 API 限制,不支持重定位以变量或插值开头的 url() 引用。
由于 Stylus 的 API 限制,不支持 @import 别名和 URL 重定位。
你也可以通过在文件扩展名前添加 .module 来结合使用 CSS modules 和预处理器,例如 style.module.scss。
禁用 CSS 注入页面
可以通过 ?inline 查询参数关闭 CSS 内容的自动注入。在这种情况下,处理后的 CSS 字符串将像往常一样作为模块的默认导出返回,但样式不会注入到页面中。
import './foo.css' // will be injected into the page
import otherStyles from './bar.css?inline' // will not be injected注意
从 Vite 5 开始,已移除从 CSS 文件进行的默认导入和具名导入(例如 import style from './foo.css')。请改为使用 ?inline 查询。
Lightning CSS
从 Vite 4.4 开始,实验性支持 Lightning CSS。你可以通过在配置文件中添加 css.transformer: 'lightningcss' 并安装可选的 lightningcss 依赖来选择使用它。
npm add -D lightningcss如果启用,CSS 文件将由 Lightning CSS 而非 PostCSS 处理。要进行配置,可以将 Lightning CSS 选项传递给 css.lightningcss 配置选项。
要配置 CSS Modules,请使用 css.lightningcss.cssModules 而不是 css.modules(后者配置的是 PostCSS 处理 CSS modules 的方式)。
默认情况下,Vite 使用 esbuild 来压缩 CSS。Lightning CSS 也可以作为 CSS 压缩器使用,配置为 build.cssMinify: 'lightningcss'。
静态资源
导入静态资源将返回其被提供时的已解析公共 URL。
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl特殊查询可以修改资源的加载方式。
// Explicitly load assets as URL (automatically inlined depending on the file size)
import assetAsURL from './asset.js?url'// Load assets as strings
import assetAsString from './shader.glsl?raw'// Load Web Workers
import Worker from './worker.js?worker'// Web Workers inlined as base64 strings at build time
import InlineWorker from './worker.js?worker&inline'更多详情请见 静态资源处理。
JSON
JSON 文件可以直接导入——也支持具名导入。
// import the entire object
import json from './example.json'
// import a root field as named exports - helps with tree-shaking!
import { field } from './example.json'Glob 导入
Vite 支持通过特殊的 import.meta.glob 函数从文件系统导入多个模块。
const modules = import.meta.glob('./dir/*.js')以上代码将被转换为以下形式:
// code produced by vite
const modules = {
'./dir/bar.js': () => import('./dir/bar.js'),
'./dir/foo.js': () => import('./dir/foo.js'),
}然后你可以遍历 modules 对象的键来访问相应的模块。
for (const path in modules) {
modules[path]().then((mod) => {
console.log(path, mod)
})
}匹配到的文件默认通过动态导入进行懒加载,并在构建时拆分为单独的块。如果你希望直接导入所有模块(例如依赖这些模块中的副作用先执行),可以将 { eager: true } 作为第二个参数传入。
const modules = import.meta.glob('./dir/*.js', { eager: true })以上代码将被转换为以下形式:
// code produced by vite
import * as __vite_glob_0_0 from './dir/bar.js'
import * as __vite_glob_0_1 from './dir/foo.js'
const modules = {
'./dir/bar.js': __vite_glob_0_0,
'./dir/foo.js': __vite_glob_0_1,
}多个模式
第一个参数可以是一个 glob 数组,例如:
const modules = import.meta.glob(['./dir/*.js', './another/*.js'])否定模式
同样支持否定 glob 模式(以 ! 开头)。要从结果中排除某些文件,可以将排除的 glob 模式添加到第一个参数中。
const modules = import.meta.glob(['./dir/*.js', '!**/bar.js'])// code produced by vite
const modules = {
'./dir/foo.js': () => import('./dir/foo.js'),
}具名导入
可以使用 import 选项仅导入模块的部分内容。
const modules = import.meta.glob('./dir/*.js', { import: 'setup' })// code produced by vite
const modules = {
'./dir/bar.js': () => import('./dir/bar.js').then((m) => m.setup),
'./dir/foo.js': () => import('./dir/foo.js').then((m) => m.setup),
}当与 eager 结合使用时,甚至可以对这些模块启用 Tree-shaking。
const modules = import.meta.glob('./dir/*.js', {
import: 'setup',
eager: true,
})// code produced by vite:
import { setup as __vite_glob_0_0 } from './dir/bar.js'
import { setup as __vite_glob_0_1 } from './dir/foo.js'
const modules = {
'./dir/bar.js': __vite_glob_0_0,
'./dir/foo.js': __vite_glob_0_1,
}设置 import 为 default 可导入默认导出。
const modules = import.meta.glob('./dir/*.js', {
import: 'default',
eager: true,
})// code produced by vite:
import { default as __vite_glob_0_0 } from './dir/bar.js'
import { default as __vite_glob_0_1 } from './dir/foo.js'
const modules = {
'./dir/bar.js': __vite_glob_0_0,
'./dir/foo.js': __vite_glob_0_1,
}自定义查询
你也可以使用 query 选项为导入提供查询,例如将资源导入为字符串或为 URL。
const moduleStrings = import.meta.glob('./dir/*.svg', {
query: '?raw',
import: 'default',
})
const moduleUrls = import.meta.glob('./dir/*.svg', {
query: '?url',
import: 'default',
})// code produced by vite:
const moduleStrings = {
'./dir/bar.svg': () => import('./dir/bar.svg?raw').then((m) => m['default']),
'./dir/foo.svg': () => import('./dir/foo.svg?raw').then((m) => m['default']),
}
const moduleUrls = {
'./dir/bar.svg': () => import('./dir/bar.svg?url').then((m) => m['default']),
'./dir/foo.svg': () => import('./dir/foo.svg?url').then((m) => m['default']),
}你也可以提供自定义查询供其他插件使用。
const modules = import.meta.glob('./dir/*.js', {
query: { foo: 'bar', bar: true },
})基础路径
你也可以使用 base 选项为导入提供基础路径。
const modulesWithBase = import.meta.glob('./**/*.js', {
base: './base',
})// code produced by vite:
const modulesWithBase = {
'./dir/foo.js': () => import('./base/dir/foo.js'),
'./dir/bar.js': () => import('./base/dir/bar.js'),
}base 选项只能是相对于导入者文件的目录路径或相对于项目根目录的绝对路径。不支持别名和虚拟模块。
只有作为相对路径的 glob 才会被解释为相对于已解析的 base。
如果提供了 base,所有结果模块的键都会被修改为相对于该 base。
Glob 导入注意事项
请注意:
- 这是 Vite 特有的功能,不是 Web 或 ES 标准。
- Glob 模式被视为导入说明符:它们必须是相对的(以
./开头)、绝对的(以/开头,解析为相对于项目根目录)或别名路径(参见resolve.alias选项)。 - Glob 匹配通过
tinyglobby完成——请查阅其文档了解支持的 glob 模式。 - 还要注意,
import.meta.glob中的所有参数必须作为字面量传递。你不能在其中使用变量或表达式。
动态导入
类似于 glob 导入,Vite 也支持变量的动态导入。
const module = await import(`./dir/${file}.js`)注意,变量仅代表一级深度的文件名。如果 file 为 'foo/bar',导入将会失败。更多高级用法,可以使用 glob 导入功能。
还要注意,动态导入必须符合以下规则才能被打包:
- 导入必须以
./或../开头:import(`./dir/${foo}.js`)是有效的,但import(`${foo}.js`)是无效的。 - 导入必须以文件扩展名结尾:
import(`./dir/${foo}.js`)是有效的,但import(`./dir/${foo}`)是无效的。 - 导入自身目录必须指定文件名模式:
import(`./prefix-${foo}.js`)是有效的,但import(`./${foo}.js`)是无效的。
强制执行这些规则是为了防止意外导入非预期的打包文件。例如,如果没有这些规则,import(foo) 会打包文件系统中的所有内容。
WebAssembly
预编译的 .wasm 文件可以使用 ?init 导入。默认导出将是一个初始化函数,返回一个 WebAssembly.Instance 的 Promise。
import init from './example.wasm?init'
init().then((instance) => {
instance.exports.test()
})初始化函数还可以接收一个 importObject,该对象作为第二个参数传递给 WebAssembly.instantiate。
init({
imports: {
someFunc: () => {
/* ... */
},
},
}).then(() => {
/* ... */
})在生产构建中,小于 assetInlineLimit 的 .wasm 文件将被内联为 base64 字符串。否则,它们将被视为静态资源并在需要时获取。
注意
目前不支持 WebAssembly 的 ES 模块集成提案。请使用 vite-plugin-wasm 或其他社区插件来处理此需求。
对于 SSR 构建,仅支持 Node.js 兼容的运行时。
由于缺乏一种通用的加载文件方法,.wasm?init 的内部实现依赖于 node:fs 模块。这意味着该功能在 SSR 构建中仅适用于 Node.js 兼容的运行时。
访问 WebAssembly 模块
如果你需要访问 Module 对象(例如为了多次实例化它),请使用显式 URL 导入来解析资源,然后进行实例化。
import wasmUrl from 'foo.wasm?url'
const main = async () => {
const responsePromise = fetch(wasmUrl)
const { module, instance } =
await WebAssembly.instantiateStreaming(responsePromise)
/* ... */
}
main()Web Workers
使用构造函数导入
Web worker 脚本可以使用 new Worker() 和 new SharedWorker() 进行导入。相比 worker 后缀,这种语法更接近标准,是创建 worker 的推荐方式。
const worker = new Worker(new URL('./worker.js', import.meta.url))Worker 构造函数也接受选项,可用于创建“模块化”worker:
const worker = new Worker(new URL('./worker.js', import.meta.url), {
type: 'module',
})只有当 new URL() 构造函数直接用于 new Worker() 声明内时,worker 检测才会生效。此外,所有选项参数必须是静态值(即字符串字面量)。
使用查询后缀导入
通过在导入请求后附加 ?worker 或 ?sharedworker,可以直接导入 Web worker 脚本。默认导出将是一个自定义 worker 构造函数:
import MyWorker from './worker?worker'
const worker = new MyWorker()Worker 脚本也可以使用 ESM import 语句而不是 importScripts()。注意:在开发阶段,这依赖于浏览器原生支持,但在生产构建中,它会被编译掉。
默认情况下,worker 脚本将在生产构建中作为单独的 chunk 输出。如果你希望将 worker 内联为 base64 字符串,请添加 inline 查询:
import MyWorker from './worker?worker&inline'如果你希望将 worker 作为 URL 获取,请添加 url 查询:
import MyWorker from './worker?worker&url'有关配置所有 worker 打包的详细信息,请参阅 Worker 选项。
内容安全策略 (CSP)
为了部署 CSP,由于 Vite 的内部机制,必须设置某些指令或配置。
'nonce-{RANDOM}'
当设置了 html.cspNonce 时,Vite 会为任何 <script> 和 <style> 标签,以及用于样式表和模块预加载的 <link> 标签添加带有指定值的 nonce 属性。此外,设置此选项后,Vite 将注入一个 meta 标签(<meta property="csp-nonce" nonce="PLACEHOLDER" />)。
无论是在开发过程中还是构建后,Vite 在必要时都会使用 property="csp-nonce" 的 meta 标签中的 nonce 值。
警告
确保每次请求都将占位符替换为唯一值。这一点至关重要,否则极易绕过资源的安全策略。
data:
默认情况下,在构建期间,Vite 会将小资源内联为数据 URI。因此,必须为相关指令(如 img-src、font-src)允许 data:,或者通过设置 build.assetsInlineLimit: 0 来禁用它。
警告
请勿为 script-src 允许 data:,这将允许注入任意脚本。
许可证
Vite 可以使用 build.license 选项生成构建中使用的所有依赖项的许可证文件。它可以被托管以展示并声明应用所使用的依赖项。
import { defineConfig } from 'vite'
export default defineConfig({
build: {
license: true,
},
})这将生成一个 .vite/license.md 文件,其输出可能如下所示:
# Licenses
The app bundles dependencies which contain the following licenses:
## dep-1 - 1.2.3 (CC0-1.0)
CC0 1.0 Universal
...
## dep-2 - 4.5.6 (MIT)
MIT License
...若要在不同路径下提供该文件,你可以传递 { fileName: 'license.md' },这样它就会在 https://example.com/license.md 下提供。有关更多信息,请参阅 build.license 文档。
构建优化
下列功能作为构建过程的一部分自动应用,无需显式配置,除非你想禁用它们。
CSS 代码分割
Vite 会自动提取异步块(async chunk)中使用的 CSS 并生成一个单独的文件。当相关的异步块被加载时,CSS 文件会自动通过 <link> 标签加载,并且保证异步块仅在 CSS 加载后才会被评估,以避免 FOUC(无样式内容闪烁)。
如果你更希望将所有 CSS 提取到单个文件中,可以通过设置 build.cssCodeSplit 为 false 来禁用 CSS 代码分割。
预加载指令生成
Vite 会自动为构建后的 HTML 中的入口 chunk 及其直接导入生成 <link rel="modulepreload"> 指令。
异步块加载优化
在实际应用中,Rollup 经常会生成“公共”块——即两个或多个其他 chunk 共享的代码。结合动态导入,出现以下场景非常普遍:
在非优化场景下,当异步块 A 被导入时,浏览器必须先请求并解析 A,才能发现它还需要公共块 C。这会导致额外的网络往返。
Entry ---> A ---> CVite 会自动重写代码分割的动态导入调用,增加一个预加载步骤,以便在请求 A 时,并行获取 C。
Entry ---> (A + C)C 可能还有进一步的导入,这在未优化场景下会导致更多往返。Vite 的优化将追踪所有直接导入,以彻底消除这些往返,无论导入深度如何。
