fix: cache transform results in getTestDependencies across projects (fix #9855)#9936
fix: cache transform results in getTestDependencies across projects (fix #9855)#9936seanogdev wants to merge 3 commits intovitest-dev:mainfrom
getTestDependencies across projects (fix #9855)#9936Conversation
When running `vitest related` with multiple projects, `getTestDependencies` called `transformRequest` for each project on shared files. This caused plugins with module-level caches (like `@vitejs/plugin-vue`'s `descriptorCache`) to be poisoned when the same file was transformed by multiple Vite server instances. Adds a `transformCache` that shares dependency results across all specs within a single `filterTestsBySource` call, so each file is only transformed once during dependency analysis. Closes vitest-dev#9855
✅ Deploy Preview for vitest-dev ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
| if (!transformed) { | ||
| return | ||
| let dependencies: string[] | ||
| const cached = transformCache?.get(filepath) |
There was a problem hiding this comment.
Doesn't this cause issues if two Vite plugins transform the same file differently? For example if your Node tests dropped some browser specific module imports, the browser tests would get the cached version and see incorrect test dependencies.
There was a problem hiding this comment.
The cache just stores import paths, not transformed code, so different plugin output shouldnt matter here. Issue is probably upstream. But I don't see a harm with this either.
There was a problem hiding this comment.
The transformed code can have different dependencies though depending on the plugin
Prevents cross-project cache poisoning when different Vite plugins transform the same file differently per project.
This reverts commit 72b0764.
Summary
When running
vitest relatedwith multiple projects,getTestDependenciescallstransformRequeston shared files through each project's Vite server independently. This triggers a bug in@vue/compiler-sfcwhere module-level LRU caches (parseCacheandtemplateAnalysisCache) get desynced across servers, causing compiled output to silently drop template-only component imports.Reproduction: https://github.com/seanogdev/vue-sfc-cache-poisoning-repro
The problem
@vue/compiler-sfchas three interacting issues:compiler.parse()returns cached mutable descriptor objects via an LRU(500), shared across all Vite servers in the processcompileTemplate()mutatesdescriptor.template.astin place, turning v-if elements (type=1) into IfNodes (type=9)resolveTemplateAnalysisResult()only walksnode.type === 1, so when it re-walks a mutated AST after cache eviction it misses components inside v-if/v-forIn a workspace with a jsdom project and a browser/Playwright project sharing
@vitejs/plugin-vue, the redundanttransformRequestcalls fromgetTestDependenciescause these caches to desync. The result:<script setup>components used only in<template>get excluded from__returned__and becomeundefinedat runtime ("Invalid vnode type" errors).Running
vitest relatedwith both projects caused browser test failures. Runningvitest related --project <storybook-only>passed cleanly, confirming the cross-project interaction.The potential fix
A shared
Map<string, string[]>caches each file's resolved import paths across all specs within a singlefilterTestsBySourcecall. The cache only stores dependency lists (import paths fromdeps/dynamicDeps), not transformed code. This means each file is only transformed once during dependency analysis, preventing the redundanttransformRequestcalls that trigger the upstream cache desync.Test plan
test/cli/test/vue-sfc-cache-poisoning.test.tsverifies thecompiler-sfccache poisoning mechanism directly using the compiler APICloses #9855