news 2026/9/14 17:54:39

Vitest deps 配置完全指南:依赖解析、预打包优化与 CJS 互操作

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vitest deps 配置完全指南:依赖解析、预打包优化与 CJS 互操作

Vitest deps 配置完全指南:依赖解析、预打包优化与 CJS 互操作

【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest

Vitest 的test.deps配置是控制测试运行器如何处理外部依赖的核心入口,它决定了依赖是否被预打包优化、资源文件与 CSS 如何处理、CommonJS 模块如何互操作,以及vi.mock如何定位模拟文件。本文基于 Vitest 官方配置文档并结合仓库源码,逐项拆解deps.optimizerdeps.clientdeps.interopDefaultdeps.moduleDirectories四组选项的语义、默认值、适用场景与底层实现,帮助你在真实项目中精准调优依赖处理行为。

deps 配置总览

deps是一个复合配置对象,类型为{ optimizer?, ... },专门负责**依赖解析(dependency resolution)**的处理策略。在仓库源码中,它的完整类型定义位于 packages/vitest/src/node/config/serializeConfig.ts 对应的类型文件 packages/vitest/src/node/types/config.ts:

interface DepsOptions { optimizer?: Partial<Record<'client' | 'ssr' | ({} & string), DepsOptimizationOptions>> web?: { transformAssets?: boolean transformCss?: boolean transformGlobPattern?: RegExp | RegExp[] } interopDefault?: boolean moduleDirectories?: string[] }

版本说明:本文关联的官方文档以deps.client指代「浏览器(client)环境下的资源处理选项」,而在当前仓库源码中,这一组选项在类型定义、配置序列化与运行时读取时统一使用deps.web命名(见 serializeConfig.ts 中的web: config.deps.web || {})。二者指向同一组配置语义,阅读源码时请注意这一命名差异。

该配置的默认值在 resolveConfig.ts 中统一补齐:

resolved.deps ??= {} resolved.deps.moduleDirectories ??= [] resolved.deps.optimizer ??= {} resolved.deps.optimizer.ssr ??= {} resolved.deps.optimizer.ssr.enabled ??= false resolved.deps.optimizer.client ??= {} resolved.deps.optimizer.client.enabled ??= false resolved.deps.web ??= {} resolved.deps.web.transformAssets ??= true resolved.deps.web.transformCss ??= true resolved.deps.web.transformGlobPattern ??= []

可以看到deps的默认行为是:不开启依赖预打包enabled均为false)、默认处理资源与 CSS 文件默认启用 CJS 互操作

deps.optimizer:依赖预打包优化

  • 类型{ ssr?, client? }
  • 核心思想:将include中列出的外部库通过 esbuild 打包成单个文件,并以整体模块的方式导入。

当你的测试很多时,开启依赖优化可能显著提升测试性能。Vitest 遇到include中列出的外部库时,会将其打包为一个文件整体导入,这带来几点好处:

  1. 减少导入开销:导入包含大量内部依赖的包非常昂贵,打包成一个文件可以节省大量时间;
  2. 解决 UI 库的运行环境问题:UI 库并非为在 Node.js 中运行而设计,预打包使其能被正确加载;
  3. alias 配置生效:你的alias配置在被打包的依赖内部同样生效;
  4. 更贴近浏览器运行行为:测试中的代码运行方式更接近真实浏览器环境。

使用前提与模式选择

需要特别注意的是,只有deps.optimizer?.[mode].include中列出的包才会被预打包(部分插件如 Svelte 会自动填充该列表)。Vitest 对 Vite 的依赖优化选项做了裁剪:不支持disablenoDiscovery两个选项,其余选项可参考 Vite 的 Dep Optimization Options 文档。

默认情况下,Vitest 对环境的映射规则如下:

测试环境使用的优化配置
jsdomhappy-domoptimizer.client
nodeedgeoptimizer.ssr

该选项还会继承你的optimizeDeps配置:对 Web 环境(client)扩展optimizeDeps,对 SSR 环境扩展ssr.optimizeDeps。如果你在deps.optimizer中重新定义了include/exclude,运行测试时它会在optimizeDeps的基础上进行扩展;同时 Vitest 会自动将exclude中出现的条目从include中移除,避免冲突。

调试时的注意事项

::: tip 开启预打包后,你将无法直接编辑node_modules中的代码进行调试——因为实际运行的代码位于cacheDirtest.cache.dir目录下。如果你需要用console.log调试,有两个选择:直接编辑缓存目录中的代码,或使用deps.optimizer?.[mode].force选项强制重新打包。 :::

deps.optimizer.{mode}.enabled

  • 类型boolean
  • 默认值false

单独控制某个模式(clientssr)是否启用依赖优化。需要与include列表配合使用才能生效。

import { defineConfig } from 'vitest/config' export default defineConfig({ test: { deps: { optimizer: { client: { enabled: true, include: ['lodash-es', 'some-ui-library'], }, ssr: { enabled: true, include: ['node-fetch'], }, }, }, }, })

从实现看,序列化时 serializeConfig.ts 仅将每个模式的enabled标志透传给 worker,实际的打包与依赖图处理由 Vite 的优化管线完成。

deps.client(源码中为 deps.web):客户端资源处理

  • 类型{ transformAssets?, ... }

这组选项作用于环境设置为client时的外部文件。默认情况下jsdomhappy-dom使用client环境,nodeedge使用ssr环境,因此这些选项对后两者环境中的文件不产生影响。

通常node_modules中的文件会被外部化(externalize)处理,但这组选项同样会影响server.deps.external中列出的文件。

deps.client.transformAssets

  • 类型boolean
  • 默认值true

控制 Vitest 是否像浏览器中的 Vite 那样处理资源文件(.png.svg.jpg等)并解析它们。当未指定 query 参数时,这类模块的默认导出等于资源文件的路径

deps.client.transformCss

  • 类型boolean
  • 默认值true

控制 Vitest 是否像浏览器中的 Vite 那样处理 CSS 文件(.css.scss.sass等)。如果 CSS 已被css选项禁用,该选项只会静默ERR_UNKNOWN_FILE_EXTENSION错误。

deps.client.transformGlobPattern

  • 类型RegExp | RegExp[]
  • 默认值[]

用于匹配应该被转换的外部文件的正则表达式。默认情况下,node_modules内的文件会被外部化且不经过转换,除非它是 CSS 或资源文件且对应选项未被禁用。

运行时实现与池限制

::: warning 目前这组选项仅对vmThreadsvmForks两种池生效,使用默认的threads/forks池时这些选项不会起作用。 :::

从源码可以清晰看到其作用机制。在 packages/vitest/src/runtime/vm/vite-executor.ts 中,canResolve方法读取 worker 状态中的config.deps?.web配置,依次判断 CSS、资源与自定义正则模式:

public canResolve = (fileUrl: string): boolean => { if (fileUrl === CLIENT_FILE) { return true } const config = this.workerState.config.deps?.web || {} const [modulePath] = fileUrl.split('?') if (config.transformCss && CSS_LANGS_RE.test(modulePath)) { return true } if (config.transformAssets && KNOWN_ASSET_RE.test(modulePath)) { return true } if ( toArray(config.transformGlobPattern).some(pattern => pattern.test(modulePath), ) ) { return true } return false }

即:当资源/CSS 文件或匹配transformGlobPattern的文件被请求时,Vitest 会将其交给 Vite 转换管线(走完整的转换与模块缓存),而不是按外部化模块直接以 Node 原生方式导入。这解释了为什么这些能力绑定在基于 VM 的池实现中。

deps.interopDefault:CJS 模块互操作

  • 类型boolean
  • 默认值true

将 CJS 模块的default导出解释为命名导出。部分依赖只打包 CJS 格式且不提供 Node.js 能静态分析的命名导出。当你在 Node 环境下用import语法(而非require)导入这类依赖并使用命名导出时,会看到如下错误:

import { read } from 'fs-jetpack'; ^^^^ SyntaxError: Named export 'read' not found. The requested module 'fs-jetpack' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export.

由于 Vitest 不做静态分析,无法在运行代码前失败,所以如果关闭该功能,你大概率会在测试运行时看到这类错误:

TypeError: createAsyncThunk is not a function TypeError: default is not a function

默认情况下,Vitest 假定你使用打包器来规避这个问题,因此不会报错;但如果你的代码未经处理,可以手动关闭该行为:

import { defineConfig } from 'vitest/config' export default defineConfig({ test: { deps: { interopDefault: false, }, }, })

从实现看,该选项通过配置序列化透传给执行器,在 packages/vitest/src/runtime/external-executor.ts 中用于外部模块执行时的默认导出处理,从而决定是否将 CJS 的module.exports整体作为default导出并展开为命名导出。

deps.moduleDirectories:模块目录解析

  • 类型string[]
  • 默认值['node_modules']

一个应被当作模块目录的目录列表。该配置影响两处行为:

  1. vi.mock的解析:当未提供 factory 且被 mock 的路径匹配某个moduleDirectories值时,Vitest 会在项目的 root 下查找__mocks__文件夹来解析 mock(详见vi.mock);
  2. 依赖外部化判定:该选项还会影响一个文件是否应被当作模块进行外部化。默认情况下,Vitest 对node_modules等模块目录中的依赖使用 Node 原生方式导入,绕过 Vite 的转换步骤。

设置该选项会覆盖默认值。如果你希望继续搜索node_modules,需要把它与其他选项一起列出:

import { defineConfig } from 'vitest/config' import path from 'node:path' export default defineConfig({ test: { deps: { moduleDirectories: ['node_modules', path.resolve('../../packages')], } }, })

该配置在解析阶段会用于项目的模块解析上下文(参见 packages/vitest/src/node/resolver.ts),同时在项目配置传递时被读取(在 test/e2e/test/projects.test.ts 等端到端测试中可以看到project.config.deps.moduleDirectories的使用,用于验证多项目场景下的解析行为)。

小结:合理组合使用 deps 配置

配置项默认值核心作用关键约束
deps.optimizer.{mode}.enabledfalse开启依赖预打包提升性能仅打包include中的库;不支持disable/noDiscovery
deps.client.transformAssetstrue像浏览器一样处理资源文件vmThreads/vmForks池生效
deps.client.transformCsstrue像浏览器一样处理 CSS 文件vmThreads/vmForks池生效
deps.client.transformGlobPattern[]用正则指定需转换的外部文件vmThreads/vmForks池生效
deps.interopDefaulttrue将 CJSdefault解释为命名导出关闭后对未处理的 CJS 依赖会运行时报错
deps.moduleDirectories['node_modules']定义模块目录,影响vi.mock与外部化设置即覆盖默认值,需手动保留node_modules

实际项目中的常见组合是:测试量大时开启deps.optimizer并维护include白名单;在vmThreads/vmForks池下测试含资源导入的组件时,保持transformAssets/transformCsstrue;遇到 CJS 依赖导入报错时优先排查interopDefault是否被误关闭;使用 monorepo 时通过moduleDirectories将本地 packages 目录纳入模块解析。理解这些选项的底层实现(配置解析、序列化与 VM 执行器),能让你在遇到依赖相关的疑难报错时快速定位根因。

【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 17:53:56

如何为自研库用 stubtest 验证 .pyi 存根与实现的一致性?

如何为自研库用 stubtest 验证 .pyi 存根与实现的一致性&#xff1f; 【免费下载链接】mypy Optional static typing for Python 项目地址: https://gitcode.com/GitHub_Trending/my/mypy 如果你给自研 Python 库维护了一份 .pyi 存根文件&#xff0c;最常见的风险是&am…

作者头像 李华
网站建设 2026/9/14 17:52:00

MV3插件开发:从脚本到工程化架构实战指南

1. MV3 不是“升级补丁”&#xff0c;而是浏览器插件的工业革命分水岭你可能刚在 Chrome Web Store 看到某个插件突然弹出“此扩展已更新至 Manifest V3”提示&#xff0c;顺手点了确认——但这个看似平静的弹窗背后&#xff0c;是一场持续三年、波及全球数百万插件开发者、彻底…

作者头像 李华
网站建设 2026/9/14 17:51:25

Vue虚拟滚动实战:解决上万条DOM渲染卡顿

在业务里碰到过一次很典型的场景&#xff1a;后台管理系统里的日志列表&#xff0c;一天就能攒下几万条数据&#xff0c;接到页面上直接一次性渲染。页面大概卡了三四秒才出来&#xff0c;滚动的时候帧率掉到个位数&#xff0c;CPU直接拉满&#xff0c;风扇响得跟起飞一样。后来…

作者头像 李华
网站建设 2026/9/14 17:51:09

鱼群算法与响应面法结合的工艺参数优化实践

1. 项目概述&#xff1a;鱼群算法与响应面法的工艺参数优化方案在工业生产与实验研究中&#xff0c;工艺参数优化一直是提升产品质量与生产效率的核心环节。传统试错法不仅耗时费力&#xff0c;而且难以找到全局最优解。本文将介绍一种融合鱼群算法&#xff08;Fish School Sea…

作者头像 李华
网站建设 2026/9/14 17:50:12

鸿蒙TextInput组件键盘弹出控制方案详解

1. 问题现象与场景还原在鸿蒙应用开发中&#xff0c;TextArea和TextInput组件是处理用户文本输入的核心控件。近期不少开发者反馈一个特定场景下的交互问题&#xff1a;当用户点击这两个组件获取光标时&#xff0c;系统键盘会自动弹出&#xff0c;但在某些业务场景下这并不是期…

作者头像 李华