Skip to content

Commit 2e7892c

Browse files
authoredDec 6, 2022
fix: correctly resolve filename, when running code (#2439)
* fix: correctly resolve filename, when running code * fix: update lastHMRTimestamp to enable caching * chore: make test files unique * test: fix flacky shard test * chore: use consistent id, when transforming module * fix: use filepath for c8 coverage * fix: ensure correct caching, if fsPath and filepath are different * chore: check fsPath as clean url * chore: ignore error on wrong cache * chore: ignore paths with query instead
1 parent 8595c0e commit 2e7892c

File tree

7 files changed

+59
-32
lines changed

7 files changed

+59
-32
lines changed
 

‎packages/coverage-c8/src/provider.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,13 @@ export class C8CoverageProvider implements CoverageProvider {
5858
if (!map)
5959
return
6060

61-
const url = _url.pathToFileURL(file.split('?')[0]).href
61+
const filepath = result.file || file.split('?')[0]
62+
63+
const url = _url.pathToFileURL(filepath).href
6264

6365
let code: string | undefined
6466
try {
65-
code = (await fs.readFile(file)).toString()
67+
code = (await fs.readFile(filepath)).toString()
6668
}
6769
catch { }
6870

‎packages/vite-node/src/client.ts

+24-17
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export class ViteNodeRunner {
191191
async directRequest(id: string, fsPath: string, _callstack: string[]) {
192192
const callstack = [..._callstack, fsPath]
193193

194-
const mod = this.moduleCache.get(fsPath)
194+
let mod = this.moduleCache.get(fsPath)
195195

196196
const request = async (dep: string) => {
197197
const depFsPath = toFilePath(normalizeRequestId(dep, this.options.base), this.root)
@@ -222,11 +222,6 @@ export class ViteNodeRunner {
222222
Object.defineProperty(request, 'callstack', { get: () => callstack })
223223

224224
const resolveId = async (dep: string, callstackPosition = 1) => {
225-
// probably means it was passed as variable
226-
// and wasn't transformed by Vite
227-
// or some dependency name was passed
228-
// runner.executeFile('@scope/name')
229-
// runner.executeFile(myDynamicName)
230225
if (this.options.resolveId && this.shouldResolveId(dep)) {
231226
let importer = callstack[callstack.length - callstackPosition]
232227
if (importer && importer.startsWith('mock:'))
@@ -238,14 +233,30 @@ export class ViteNodeRunner {
238233
return dep
239234
}
240235

241-
id = await resolveId(id, 2)
242-
243236
const requestStubs = this.options.requestStubs || DEFAULT_REQUEST_STUBS
244237
if (id in requestStubs)
245238
return requestStubs[id]
246239

247240
// eslint-disable-next-line prefer-const
248-
let { code: transformed, externalize } = await this.options.fetchModule(id)
241+
let { code: transformed, externalize, file } = await this.options.fetchModule(id)
242+
243+
// in case we resolved fsPath incorrectly, Vite will return the correct file path
244+
// in that case we need to update cache, so we don't have the same module as different exports
245+
// but we ignore fsPath that has custom query, because it might need to be different
246+
if (file && !fsPath.includes('?') && fsPath !== file) {
247+
if (this.moduleCache.has(file)) {
248+
mod = this.moduleCache.get(file)
249+
this.moduleCache.set(fsPath, mod)
250+
if (mod.promise)
251+
return mod.promise
252+
if (mod.exports)
253+
return mod.exports
254+
}
255+
else {
256+
this.moduleCache.set(file, mod)
257+
}
258+
}
259+
249260
if (externalize) {
250261
debugNative(externalize)
251262
const exports = await this.interopedImport(externalize)
@@ -257,19 +268,16 @@ export class ViteNodeRunner {
257268
throw new Error(`[vite-node] Failed to load ${id}`)
258269

259270
// disambiguate the `<UNIT>:/` on windows: see nodejs/node#31710
260-
const url = pathToFileURL(fsPath).href
271+
const url = pathToFileURL(file || fsPath).href
261272
const meta = { url }
262-
const exports: any = Object.create(null)
273+
const exports = Object.create(null)
263274
Object.defineProperty(exports, Symbol.toStringTag, {
264275
value: 'Module',
265276
enumerable: false,
266277
configurable: false,
267278
})
268279
// this prosxy is triggered only on exports.name and module.exports access
269280
const cjsExports = new Proxy(exports, {
270-
get(_, p, receiver) {
271-
return Reflect.get(exports, p, receiver)
272-
},
273281
set(_, p, value) {
274282
if (!Reflect.has(exports, 'default'))
275283
exports.default = {}
@@ -289,8 +297,7 @@ export class ViteNodeRunner {
289297
},
290298
})
291299

292-
Object.assign(mod, { code: transformed, exports, evaluated: false })
293-
300+
Object.assign(mod, { code: transformed, exports })
294301
const __filename = fileURLToPath(url)
295302
const moduleProxy = {
296303
set exports(value) {
@@ -345,7 +352,7 @@ export class ViteNodeRunner {
345352
const codeDefinition = `'use strict';async (${Object.keys(context).join(',')})=>{{`
346353
const code = `${codeDefinition}${transformed}\n}}`
347354
const fn = vm.runInThisContext(code, {
348-
filename: fsPath,
355+
filename: __filename,
349356
lineOffset: 0,
350357
columnOffset: -codeDefinition.length,
351358
})

‎packages/vite-node/src/server.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@ import type { TransformResult, ViteDevServer } from 'vite'
44
import createDebug from 'debug'
55
import type { DebuggerOptions, FetchResult, RawSourceMap, ViteNodeResolveId, ViteNodeServerOptions } from './types'
66
import { shouldExternalize } from './externalize'
7-
import { toArray, toFilePath } from './utils'
7+
import { cleanUrl, normalizeModuleId, toArray, toFilePath } from './utils'
88
import { Debugger } from './debug'
99
import { withInlineSourcemap } from './source-map'
1010

1111
export * from './externalize'
1212

1313
const debugRequest = createDebug('vite-node:server:request')
1414

15-
// store the original reference to avoid it been mocked
16-
const RealDate = Date
17-
1815
export class ViteNodeServer {
1916
private fetchPromiseMap = new Map<string, Promise<FetchResult>>()
2017
private transformPromiseMap = new Map<string, Promise<TransformResult | null | undefined>>()
@@ -83,6 +80,7 @@ export class ViteNodeServer {
8380
}
8481

8582
async fetchModule(id: string): Promise<FetchResult> {
83+
id = normalizeModuleId(id)
8684
// reuse transform for concurrent requests
8785
if (!this.fetchPromiseMap.has(id)) {
8886
this.fetchPromiseMap.set(id,
@@ -130,27 +128,36 @@ export class ViteNodeServer {
130128
const filePath = toFilePath(id, this.server.config.root)
131129

132130
const module = this.server.moduleGraph.getModuleById(id)
133-
const timestamp = module?.lastHMRTimestamp || RealDate.now()
131+
const timestamp = module ? module.lastHMRTimestamp : null
134132
const cache = this.fetchCache.get(filePath)
135-
if (timestamp && cache && cache.timestamp >= timestamp)
133+
if (cache?.result.id)
134+
id = cache.result.id
135+
if (timestamp !== null && cache && cache.timestamp >= timestamp)
136136
return cache.result
137137

138+
const time = Date.now()
138139
const externalize = await this.shouldExternalize(filePath)
139140
let duration: number | undefined
140141
if (externalize) {
141142
result = { externalize }
142143
this.debugger?.recordExternalize(id, externalize)
143144
}
144145
else {
146+
let file = module?.file
147+
if (!file) {
148+
const [, resolvedId] = await this.server.moduleGraph.resolveUrl(id, true)
149+
id = resolvedId
150+
file = cleanUrl(resolvedId)
151+
}
145152
const start = performance.now()
146153
const r = await this._transformRequest(id)
147154
duration = performance.now() - start
148-
result = { code: r?.code, map: r?.map as unknown as RawSourceMap }
155+
result = { file, id, code: r?.code, map: r?.map as unknown as RawSourceMap }
149156
}
150157

151158
this.fetchCache.set(filePath, {
152159
duration,
153-
timestamp,
160+
timestamp: time,
154161
result,
155162
})
156163

‎packages/vite-node/src/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface FetchResult {
3131
code?: string
3232
externalize?: string
3333
map?: RawSourceMap
34+
id?: string
35+
file?: string
3436
}
3537

3638
export type HotContext = Omit<ViteHotContext, 'acceptDeps' | 'decline'>

‎packages/vite-node/src/utils.ts

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ export function normalizeRequestId(id: string, base?: string): string {
3434
.replace(/\?+$/, '') // remove end query mark
3535
}
3636

37+
export const queryRE = /\?.*$/s
38+
export const hashRE = /#.*$/s
39+
40+
export const cleanUrl = (url: string): string =>
41+
url.replace(hashRE, '').replace(queryRE, '')
42+
3743
export function normalizeModuleId(id: string) {
3844
return id
3945
.replace(/\\/g, '/')

‎packages/vitest/src/node/core.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,7 @@ export class Vitest {
115115
try {
116116
await this.cache.results.readFromCache()
117117
}
118-
catch (err) {
119-
this.logger.error(`[vitest] Error, while trying to parse cache in ${this.cache.results.getCachePath()}:`, err)
120-
}
118+
catch {}
121119
}
122120

123121
async initCoverageProvider() {
@@ -311,6 +309,8 @@ export class Vitest {
311309
}
312310

313311
async runFiles(paths: string[]) {
312+
paths = Array.from(new Set(paths))
313+
314314
// previous run
315315
await this.runningPromise
316316
this.state.startCollectingPaths()
@@ -396,6 +396,9 @@ export class Vitest {
396396

397397
private _rerunTimer: any
398398
private async scheduleRerun(triggerId: string) {
399+
const mod = this.server.moduleGraph.getModuleById(triggerId)
400+
if (mod)
401+
mod.lastHMRTimestamp = Date.now()
399402
const currentCount = this.restartsCount
400403
clearTimeout(this._rerunTimer)
401404
await this.runningPromise

‎test/shard/shard-test.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ const runVitest = async (args: string[]) => {
88
}
99

1010
const parsePaths = (stdout: string) => {
11-
return stdout
11+
return Array.from(new Set(stdout
1212
.split('\n')
1313
.filter(line => line && line.includes('.test.js'))
1414
.map(file => basename(file.trim().split(' ')[1]))
15-
.sort()
15+
.sort()))
1616
}
1717

1818
test('--shard=1/1', async () => {

0 commit comments

Comments
 (0)
Please sign in to comment.