依赖预构建
当你首次运行 vite 时,Vite 会在本地加载站点之前预构建项目依赖。此过程默认自动且透明地完成。
为什么需要预构建
这就是 Vite 所称的“依赖预构建”。该过程主要有两个目的:
CommonJS 和 UMD 兼容性: 在开发过程中,Vite 将所有代码作为原生 ESM 提供。因此,Vite 必须先将以 CommonJS 或 UMD 格式发布的依赖项转换为 ESM。
在转换 CommonJS 依赖时,Vite 会执行智能导入分析,确保对 CommonJS 模块的具名导入能按预期工作,即使导出是动态分配的(例如 React)。
js// works as expected import React, { useState } from 'react'性能: Vite 将包含大量内部模块的 ESM 依赖转换为单个模块,以提高后续页面的加载性能。
一些包将它们的 ES 模块构建为许多相互导入的独立文件。例如,
lodash-es有超过 600 个内部模块!当我们执行import { debounce } from 'lodash-es'时,浏览器会同时发出 600 多个 HTTP 请求!虽然服务器处理这些请求没有问题,但大量的请求会在浏览器端造成网络拥塞,导致页面加载明显变慢。通过将
lodash-es预构建为单个模块,我们现在只需要一个 HTTP 请求!
注意
依赖预构建仅适用于开发模式。
自动依赖发现
如果未找到现有缓存,Vite 会抓取你的源代码并自动发现依赖项导入(即预期从 node_modules 解析的“裸导入”),并将这些发现的导入作为预构建的入口点。预构建过程由 Rolldown 执行,因此通常非常快。
服务器启动后,如果遇到了缓存中不存在的新依赖导入,Vite 将重新运行依赖构建过程,并在必要时重新加载页面。
Monorepos 和链接依赖
在 Monorepo 设置中,依赖项可能是来自同一仓库的链接包。Vite 会自动检测未从 node_modules 解析的依赖项,并将其视为源代码。它不会尝试构建该链接依赖,而是会分析该链接依赖的依赖列表。
但是,这要求链接的依赖项必须导出为 ESM。如果不是,你可以将其添加到配置文件的 optimizeDeps.include 中。
export default defineConfig({
optimizeDeps: {
include: ['linked-dep'],
},
})对链接的依赖项进行更改时,请使用 --force 命令行选项重启开发服务器以使更改生效。
自定义行为
默认的依赖发现启发式算法并不总是理想的。如果你想显式地包含或排除某些依赖项,请使用 optimizeDeps 配置选项。
optimizeDeps.include 或 optimizeDeps.exclude 的典型用例是当你有一个在源代码中无法直接发现的导入时。例如,该导入可能是插件转换的结果。这意味着 Vite 无法在初始扫描时发现它——只能在浏览器请求并转换该文件后才能发现。这将导致服务器在启动后立即重新构建。
include 和 exclude 都可以用来处理这种情况。如果依赖项很大(包含许多内部模块)或者是 CommonJS,则应该将其包含进来;如果依赖项很小且已经是有效的 ESM,你可以将其排除,让浏览器直接加载它。
你还可以通过 optimizeDeps.rolldownOptions 选项进一步自定义 Rolldown。例如,添加一个 Rolldown 插件来处理依赖项中的特殊文件,或更改 构建 target。
缓存
文件系统缓存
Vite 将预构建的依赖项缓存在 node_modules/.vite 中。它基于以下几个来源确定是否需要重新运行预构建步骤:
- 包管理器的锁文件内容,例如
package-lock.json、yarn.lock、pnpm-lock.yaml或bun.lock。 - 补丁文件夹的修改时间。
vite.config.js中的相关字段(如果存在)。NODE_ENV的值。
预构建步骤仅在上述任一项发生更改时才会重新运行。
如果由于某种原因你想要强制 Vite 重新构建依赖项,可以启动开发服务器时带上 --force 命令行选项,或者手动删除 node_modules/.vite 缓存目录。
浏览器缓存
解析后的依赖请求会通过 HTTP 头 max-age=31536000,immutable 进行强缓存,以提高开发时的页面重载性能。一旦缓存,这些请求将永远不会再次触及开发服务器。如果安装了不同版本(反映在包管理器的锁文件中),它们会自动通过附加的版本查询参数失效。如果你想通过本地编辑来调试依赖项,你可以:
- 通过浏览器开发者工具的网络选项卡临时禁用缓存。
- 使用
--force标志重启 Vite 开发服务器以重新构建依赖项。 - 重新加载页面。
