分析测试性能
当你运行 Vitest 时,它会报告测试的多个时间指标:
bashRUN v2.1.1 /x/vitest/examples/profiling ✓ test/prime-number.test.ts (1) 4517ms ✓ generate prime number 4517ms Test Files 1 passed (1) Tests 1 passed (1) Start at 09:32:53 Duration 4.80s (transform 44ms, setup 0ms, import 35ms, tests 4.52s, environment 0ms) # 时间指标 ^^
- Transform:花费在转换文件上的时间。参见 文件转换。
- Setup:运行
setupFiles文件所花费的时间。 - Import:导入测试文件及其依赖所花费的时间。这也包括收集所有测试所花费的时间。注意,这不包括测试内部的动态导入。
- Tests:实际运行测试用例所花费的时间。
- Environment:设置测试
environment所花费的时间,例如 JSDOM。
测试运行器
在测试执行时间较高的情况下,你可以生成测试运行器的性能分析文件。参见 NodeJS 文档了解以下选项:
WARNING
--prof 选项由于 node:worker_threads 的限制,无法与 pool: 'threads' 一起使用。
要将这些选项传递给 Vitest 的测试运行器,请在你的 Vitest 配置中定义 execArgv:
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
fileParallelism: false,
execArgv: [
'--cpu-prof',
'--cpu-prof-dir=test-runner-profile',
'--heap-prof',
'--heap-prof-dir=test-runner-profile'
],
},
})测试运行后,应该会生成 test-runner-profile/*.cpuprofile 和 test-runner-profile/*.heapprofile 文件。参见 检查性能分析记录 了解如何分析这些文件的说明。
参见 性能分析 | 示例 了解示例。
主线程
分析主线程对于调试 Vitest 的 Vite 用法和 globalSetup 文件很有用。 你的 Vite 插件也是在这里运行的。
为此,你需要将参数传递给运行 Vitest 的 Node 进程。
$ node --cpu-prof --cpu-prof-dir=main-profile ./node_modules/vitest/vitest.mjs --run
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^
# NodeJS 参数 Vitest 参数测试运行后,应该会生成 main-profile/*.cpuprofile 文件。参见 检查性能分析记录 了解如何分析这些文件的说明。
文件转换
这种性能分析策略是识别由 barrel 文件 引起的不必要转换的好方法。 如果这些日志包含在你的测试运行时不应加载的文件,你可能拥有不必要的导入文件的 barrel 文件。
你也可以使用 Vitest UI 来调试由 barrel 文件引起的缓慢问题。 下面的示例展示了不使用 barrel 文件导入文件如何减少约 85% 的转换文件数量。
├── src
│ └── utils
│ ├── currency.ts
│ ├── formatters.ts <-- File to test
│ ├── index.ts
│ ├── location.ts
│ ├── math.ts
│ ├── time.ts
│ └── users.ts
├── test
│ └── formatters.test.ts
└── vitest.config.tsimport { expect, test } from 'vitest'
import { formatter } from '../src/utils'
import { formatter } from '../src/utils/formatters'
test('formatter works', () => {
expect(formatter).not.toThrow()
})
要查看文件是如何转换的,你可以在 UI 中打开 "Module Info" 视图:


文件导入
有些模块加载就是需要很长时间。要识别哪些模块最慢,请在你的配置中启用 experimental.importDurations:
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
experimental: {
importDurations: {
print: true,
},
},
},
})这将在测试完成后打印最慢导入的细分情况:
Import Duration Breakdown (Top 10)
Module Self Total
my-test.test.ts 5ms 620ms [████████████████████]
date-fns/index.js 500ms 500ms [████████████████░░░░]
src/utils/helpers.ts 10ms 120ms [████████░░░░░░░░░░░░]你也可以在不更改配置的情况下从 CLI 使用 --experimental.importDurations.print:
vitest --experimental.importDurations.print一旦你识别了慢速模块,有几种策略可以加速导入:
使用特定入口点
许多库提供多个入口点。导入主入口点(通常是 barrel 文件)可能会引入远超你所需的代码。
例如,date-fns 从其主入口点重新导出了数百个函数。不要从顶层模块导入,而是直接从特定函数导入:
import { format } from 'date-fns'
import { format } from 'date-fns/format'使用 resolve.alias 重定向导入
如果依赖项不提供细粒度的入口点,或者第三方代码导入了沉重的入口点,你可以使用 resolve.alias 将导入重定向到更轻量级的替代方案:
import { defineConfig } from 'vitest/config'
export default defineConfig({
resolve: {
alias: [
{
find: /^date-fns$/,
replacement: join(dirname(require.resolve('date-fns/package.json')), 'index.cjs'),
},
]
},
})使用依赖优化器
Vitest 可以使用 deps.optimizer 将外部库捆绑到单个文件中,这减少了导入具有许多内部模块的包的开销:
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
deps: {
optimizer: {
ssr: {
enabled: true,
include: ['date-fns'],
},
},
},
},
})这对于 UI 库和具有深层导入树的包特别有效。对 node/edge 环境使用 optimizer.ssr,对 jsdom/happy-dom 环境使用 optimizer.client。
代码覆盖率
如果你的项目中代码覆盖率生成缓慢,你可以使用 DEBUG=vitest:coverage 环境变量来启用性能日志记录。
$ DEBUG=vitest:coverage vitest --run --coverage
RUN v3.1.1 /x/vitest-example
vitest:coverage Reading coverage results 2/2
vitest:coverage Converting 1/2
vitest:coverage 4 ms /x/src/multiply.ts
vitest:coverage Converting 2/2
vitest:coverage 552 ms /x/src/add.ts
vitest:coverage Uncovered files 1/2
vitest:coverage File "/x/src/large-file.ts" is taking longer than 3s
vitest:coverage 3027 ms /x/src/large-file.ts
vitest:coverage Uncovered files 2/2
vitest:coverage 4 ms /x/src/untested-file.ts
vitest:coverage Generate coverage total time 3521 ms这种性能分析方法非常适合检测被覆盖率提供者意外选取的大文件。 例如,如果你的配置意外地将大型构建后的压缩 Javascript 文件包含在代码覆盖率中,它们应该出现在日志中。 在这些情况下,你可能想要调整你的 coverage.include 和 coverage.exclude 选项。
检查性能分析记录
你可以使用各种工具检查 *.cpuprofile 和 *.heapprofile 的内容。参见下面的列表示例。
