11import type { Span } from '@opentelemetry/api'
22import type { DevEnvironment , EnvironmentModuleNode , Rollup , TransformResult } from 'vite'
33import type { FetchFunctionOptions , FetchResult } from 'vite/module-runner'
4- import type { FetchCachedFileSystemResult , VitestFetchResult } from '../../types/general'
4+ import type { FetchCachedFileSystemResult , ModuleType , VitestFetchResult } from '../../types/general'
55import type { OTELCarrier , Traces } from '../../utils/traces'
66import type { FileSystemModuleCache } from '../cache/fsModuleCache'
77import type { VitestResolver } from '../resolver'
@@ -142,7 +142,14 @@ class ModuleFetcher {
142142 const map = moduleGraphModule . transformResult ?. map
143143 const mappings = map && ! ( 'version' in map ) && map . mappings === ''
144144
145- return this . cacheResult ( result , cachePath , importedUrls , ! ! mappings )
145+ const cachedResult = await this . cacheResult ( result , cachePath , importedUrls , ! ! mappings )
146+ // remember where the code is stored on disk so that repeat fetches and the
147+ // `fetchWarmModules` snapshot can point at it in this session already, not
148+ // only after the cache is read back in the next one
149+ if ( 'code' in result && moduleGraphModule . transformResult ) {
150+ moduleGraphModule . transformResult . __vitestTmp = cachePath
151+ }
152+ return cachedResult
146153 }
147154
148155 // we need this for UI to be able to show a module graph
@@ -239,13 +246,11 @@ class ModuleFetcher {
239246 tmp : moduleGraphModule . transformResult . __vitestTmp ,
240247 url : moduleGraphModule . url ,
241248 invalidate : false ,
242- moduleType : this . detectModuleType
243- ? await detectModuleType (
244- moduleGraphModule . file ,
245- moduleGraphModule . transformResult . code ,
246- this . sourceLoader ( moduleGraphModule . file ) ,
247- )
248- : undefined ,
249+ moduleType : await this . cachedModuleType (
250+ moduleGraphModule . file ,
251+ moduleGraphModule . transformResult . code ,
252+ moduleGraphModule . transformResult ,
253+ ) ,
249254 }
250255 }
251256
@@ -264,11 +269,13 @@ class ModuleFetcher {
264269 if ( ! map && cachedModule . mappings ) {
265270 map = { mappings : '' }
266271 }
272+ const moduleType = cachedModule . moduleType
267273 moduleGraphModule . transformResult = {
268274 code : cachedModule . code ,
269275 map,
270276 ssr : true ,
271277 __vitestTmp : cachePath ,
278+ __vitestModuleType : moduleType ,
272279 }
273280
274281 // we populate the module graph to make the watch mode work because it relies on importers
@@ -294,9 +301,7 @@ class ModuleFetcher {
294301 tmp : cachePath ,
295302 url : cachedModule . url ,
296303 invalidate : false ,
297- moduleType : this . detectModuleType
298- ? await detectModuleType ( cachedModule . file , cachedModule . code , this . sourceLoader ( cachedModule . file ) )
299- : undefined ,
304+ moduleType,
300305 }
301306 }
302307
@@ -318,8 +323,8 @@ class ModuleFetcher {
318323 ) . catch ( handleRollupError )
319324
320325 const result : VitestFetchResult = processResultSource ( environment , moduleRunnerModule )
321- if ( this . detectModuleType && 'code' in result ) {
322- result . moduleType = await detectModuleType ( result . file , result . code , this . sourceLoader ( result . file ) )
326+ if ( 'code' in result ) {
327+ result . moduleType = await this . cachedModuleType ( result . file , result . code , moduleGraphModule . transformResult )
323328 }
324329 return result
325330 }
@@ -331,6 +336,28 @@ class ModuleFetcher {
331336 return ( ) => this . readFileConcurrently ( file )
332337 }
333338
339+ // the module type is a pure function of the module, so detect it at most once
340+ // and memoize the verdict on the transform result. repeat fetches, the on-disk
341+ // cache (`cached`), and the `fetchWarmModules` snapshot all reuse it instead of
342+ // re-detecting. a no-op unless `injectCjsGlobals` is disabled — otherwise every
343+ // module receives the CJS globals and the type is irrelevant.
344+ private async cachedModuleType (
345+ file : string | null ,
346+ code : string ,
347+ transformResult : TransformResult | null | undefined ,
348+ ) : Promise < ModuleType | undefined > {
349+ if ( ! this . detectModuleType ) {
350+ return undefined
351+ }
352+ const moduleType
353+ = transformResult ?. __vitestModuleType
354+ ?? await detectModuleType ( file , code , this . sourceLoader ( file ) )
355+ if ( transformResult ) {
356+ transformResult . __vitestModuleType = moduleType
357+ }
358+ return moduleType
359+ }
360+
334361 private async cacheResult (
335362 result : FetchResult ,
336363 cachePath : string ,
@@ -543,5 +570,6 @@ export function handleRollupError(e: unknown): never {
543570declare module 'vite' {
544571 export interface TransformResult {
545572 __vitestTmp ?: string
573+ __vitestModuleType ?: ModuleType
546574 }
547575}
0 commit comments