[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

feat: resolve circular dependencies

Anthony Fu (Dec 8, 2021, 7:37 PM +0800) 0bc51240 576bd8ac

+61 -20
+29 -15
src/node/node.ts
··· 7 7 8 8 const { red, dim, yellow } = c 9 9 10 + export interface ModuleCache { 11 + promise?: Promise<any> 12 + exports?: any 13 + transformResult?: TransformResult 14 + } 15 + 10 16 declare global { 11 17 namespace NodeJS { 12 18 interface Process { 13 19 __vite_node__: { 14 20 server: ViteDevServer 15 21 watch?: boolean 16 - moduleCache: Map<string, Promise<any>> 17 - modulesTransformResult: Map<string, TransformResult> 22 + moduleCache: Map<string, ModuleCache> 18 23 } 19 24 } 20 25 } 21 26 } 22 27 23 - const moduleCache = new Map<string, Promise<any>>() 24 - const modulesTransformResult = new Map<string, TransformResult>() 28 + const moduleCache = new Map<string, ModuleCache>() 25 29 26 30 export interface ViteNodeOptions { 27 31 silent?: boolean ··· 55 59 process.__vite_node__ = { 56 60 server, 57 61 moduleCache, 58 - modulesTransformResult, 59 62 } 60 63 61 64 try { ··· 126 129 } 127 130 } 128 131 132 + function setCache(id: string, mod: Partial<ModuleCache>) { 133 + if (!moduleCache.has(id)) 134 + moduleCache.set(id, mod) 135 + else 136 + Object.assign(moduleCache.get(id), mod) 137 + } 138 + 129 139 async function execute(files: string[], server: ViteDevServer, options: ViteNodeOptions) { 130 140 const result = [] 131 141 for (const file of files) ··· 136 146 callstack = [...callstack, id] 137 147 const request = async(dep: string) => { 138 148 if (callstack.includes(dep)) { 139 - throw new Error(`${red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => { 140 - const path = relative(server.config.root, toFilePath(normalizeId(i), server)) 141 - return dim(' -> ') + (i === dep ? yellow(path) : path) 142 - }).join('\n')}\n`) 149 + if (!moduleCache.get(dep)) { 150 + throw new Error(`${red('Circular dependency detected')}\nStack:\n${[...callstack, dep].reverse().map((i) => { 151 + const path = relative(server.config.root, toFilePath(normalizeId(i), server)) 152 + return dim(' -> ') + (i === dep ? yellow(path) : path) 153 + }).join('\n')}\n`) 154 + } 155 + return moduleCache.get(dep)!.exports 143 156 } 144 157 return cachedRequest(dep, callstack) 145 158 } ··· 151 164 if (!result) 152 165 throw new Error(`failed to load ${id}`) 153 166 154 - modulesTransformResult.set(id, result) 155 - 156 167 const url = pathToFileURL(fsPath) 157 168 const exports = {} 169 + 170 + setCache(id, { transformResult: result, exports }) 158 171 159 172 const context = { 160 173 require: createRequire(url), ··· 187 200 if (options.shouldExternalize!(fsPath, server)) 188 201 return import(fsPath) 189 202 190 - if (moduleCache.has(fsPath)) 191 - return moduleCache.get(fsPath) 192 - moduleCache.set(fsPath, directRequest(id, fsPath, callstack)) 193 - return await moduleCache.get(fsPath) 203 + if (moduleCache.get(fsPath)?.promise) 204 + return moduleCache.get(fsPath)?.promise 205 + const promise = directRequest(id, fsPath, callstack) 206 + setCache(fsPath, { promise }) 207 + return await promise 194 208 } 195 209 196 210 function exportAll(exports: any, sourceModule: any) {
+3 -3
src/reporters/error.ts
··· 18 18 return 19 19 } 20 20 21 - const { modulesTransformResult } = process.__vite_node__ 21 + const { moduleCache } = process.__vite_node__ 22 22 23 23 const e = error as ErrorWithDiff 24 24 25 25 let codeFramePrinted = false 26 26 const stacks = parseStack(e.stack || '') 27 - const nearest = stacks.find(stack => modulesTransformResult.has(stack.file)) 27 + const nearest = stacks.find(stack => moduleCache.has(stack.file)) 28 28 if (nearest) { 29 - const transformResult = modulesTransformResult.get(nearest.file) 29 + const transformResult = moduleCache.get(nearest.file)?.transformResult 30 30 const pos = await getOriginalPos(transformResult?.map, nearest) 31 31 if (pos && existsSync(nearest.file)) { 32 32 const sourceCode = await fs.readFile(nearest.file, 'utf-8')
+7
test/core/src/circularA.ts
··· 1 + import { circularB } from './circularB' 2 + 3 + export const CalledB: number[] = [] 4 + 5 + export function circularA() { 6 + return circularB() 7 + }
+5
test/core/src/circularB.ts
··· 1 + import { CalledB } from './circularA' 2 + 3 + export function circularB() { 4 + return CalledB.push(CalledB.length) 5 + }
+1
test/core/src/submodule.ts
··· 1 + export const two = 1 + 1
+1 -1
test/core/test/basic.test.ts
··· 1 1 import { expect, test, assert, suite } from 'vitest' 2 - import { two } from '../test/submodule' 2 + import { two } from '../src/submodule' 3 3 4 4 test('Math.sqrt()', () => { 5 5 assert.equal(Math.sqrt(4), two)
+15
test/core/test/cicular.test.ts
··· 1 + import { test, expect } from 'vitest' 2 + import { CalledB, circularA } from '../src/circularA' 3 + 4 + test('circular', () => { 5 + CalledB.length = 0 6 + 7 + circularA() 8 + 9 + expect(CalledB.length).toBe(1) 10 + 11 + circularA() 12 + circularA() 13 + 14 + expect(CalledB).toEqual([0, 1, 2]) 15 + })
-1
test/core/test/submodule.ts
··· 1 - export const two = 1 + 1