11import { createRequire } from 'module'
2+ // we need native dirname, because windows __dirname has \\
3+ // eslint-disable-next-line no-restricted-imports
4+ import { dirname } from 'path'
25import { fileURLToPath , pathToFileURL } from 'url'
36import vm from 'vm'
4- import { dirname , extname , isAbsolute , resolve } from 'pathe'
5- import { isNodeBuiltin } from 'mlly'
7+ import { resolve } from 'pathe'
68import createDebug from 'debug'
7- import { cleanUrl , isPrimitive , normalizeModuleId , normalizeRequestId , slash , toFilePath } from './utils'
9+ import { VALID_ID_PREFIX , cleanUrl , isInternalRequest , isPrimitive , normalizeModuleId , normalizeRequestId , slash , toFilePath } from './utils'
810import type { HotContext , ModuleCache , ViteNodeRunnerOptions } from './types'
911import { extractSourceMap } from './source-map'
1012
@@ -145,24 +147,24 @@ export class ViteNodeRunner {
145147 }
146148
147149 async executeFile ( file : string ) {
148- return await this . cachedRequest ( `/@fs/${ slash ( resolve ( file ) ) } ` , [ ] )
150+ const url = `/@fs/${ slash ( resolve ( file ) ) } `
151+ return await this . cachedRequest ( url , url , [ ] )
149152 }
150153
151- async executeId ( id : string ) {
152- return await this . cachedRequest ( id , [ ] )
154+ async executeId ( rawId : string ) {
155+ const [ id , url ] = await this . resolveUrl ( rawId )
156+ return await this . cachedRequest ( id , url , [ ] )
153157 }
154158
155159 getSourceMap ( id : string ) {
156160 return this . moduleCache . getSourceMap ( id )
157161 }
158162
159163 /** @internal */
160- async cachedRequest ( rawId : string , callstack : string [ ] ) {
161- const id = normalizeRequestId ( rawId , this . options . base )
162- const fsPath = toFilePath ( id , this . root )
164+ async cachedRequest ( id : string , fsPath : string , callstack : string [ ] ) {
165+ const importee = callstack [ callstack . length - 1 ]
163166
164167 const mod = this . moduleCache . get ( fsPath )
165- const importee = callstack [ callstack . length - 1 ]
166168
167169 if ( ! mod . importers )
168170 mod . importers = new Set ( )
@@ -188,79 +190,68 @@ export class ViteNodeRunner {
188190 }
189191 }
190192
193+ async resolveUrl ( id : string , importee ?: string ) : Promise < [ url : string , fsPath : string ] > {
194+ if ( isInternalRequest ( id ) )
195+ return [ id , id ]
196+ // we don't pass down importee here, because otherwise Vite doesn't resolve it correctly
197+ if ( importee && id . startsWith ( VALID_ID_PREFIX ) )
198+ importee = undefined
199+ id = normalizeRequestId ( id , this . options . base )
200+ if ( ! this . options . resolveId )
201+ return [ id , toFilePath ( id , this . root ) ]
202+ const resolved = await this . options . resolveId ( id , importee )
203+ const resolvedId = resolved
204+ ? normalizeRequestId ( resolved . id , this . options . base )
205+ : id
206+ // to be compatible with dependencies that do not resolve id
207+ const fsPath = resolved ? resolvedId : toFilePath ( id , this . root )
208+ return [ resolvedId , fsPath ]
209+ }
210+
191211 /** @internal */
192- async directRequest ( id : string , fsPath : string , _callstack : string [ ] ) {
193- const callstack = [ ..._callstack , fsPath ]
212+ async dependencyRequest ( id : string , fsPath : string , callstack : string [ ] ) {
213+ const getStack = ( ) => {
214+ return `stack:\n${ [ ...callstack , fsPath ] . reverse ( ) . map ( p => `- ${ p } ` ) . join ( '\n' ) } `
215+ }
194216
195- let mod = this . moduleCache . get ( fsPath )
217+ let debugTimer : any
218+ if ( this . debug )
219+ debugTimer = setTimeout ( ( ) => console . warn ( ( ) => `module ${ fsPath } takes over 2s to load.\n${ getStack ( ) } ` ) , 2000 )
196220
197- const request = async ( dep : string ) => {
198- const depFsPath = toFilePath ( normalizeRequestId ( dep , this . options . base ) , this . root )
199- const getStack = ( ) => {
200- return `stack:\n${ [ ...callstack , depFsPath ] . reverse ( ) . map ( p => `- ${ p } ` ) . join ( '\n' ) } `
221+ try {
222+ if ( callstack . includes ( fsPath ) ) {
223+ const depExports = this . moduleCache . get ( fsPath ) ?. exports
224+ if ( depExports )
225+ return depExports
226+ throw new Error ( `[vite-node] Failed to resolve circular dependency, ${ getStack ( ) } ` )
201227 }
202228
203- let debugTimer : any
204- if ( this . debug )
205- debugTimer = setTimeout ( ( ) => console . warn ( ( ) => `module ${ depFsPath } takes over 2s to load.\n${ getStack ( ) } ` ) , 2000 )
206-
207- try {
208- if ( callstack . includes ( depFsPath ) ) {
209- const depExports = this . moduleCache . get ( depFsPath ) ?. exports
210- if ( depExports )
211- return depExports
212- throw new Error ( `[vite-node] Failed to resolve circular dependency, ${ getStack ( ) } ` )
213- }
214-
215- return await this . cachedRequest ( dep , callstack )
216- }
217- finally {
218- if ( debugTimer )
219- clearTimeout ( debugTimer )
220- }
229+ return await this . cachedRequest ( id , fsPath , callstack )
230+ }
231+ finally {
232+ if ( debugTimer )
233+ clearTimeout ( debugTimer )
221234 }
235+ }
222236
223- Object . defineProperty ( request , 'callstack' , { get : ( ) => callstack } )
224-
225- const resolveId = async ( dep : string , callstackPosition = 1 ) : Promise < [ dep : string , id : string | undefined ] > => {
226- if ( this . options . resolveId && this . shouldResolveId ( dep ) ) {
227- let importer : string | undefined = callstack [ callstack . length - callstackPosition ]
228- if ( importer && ! dep . startsWith ( '.' ) )
229- importer = undefined
230- if ( importer && importer . startsWith ( 'mock:' ) )
231- importer = importer . slice ( 5 )
232- const resolved = await this . options . resolveId ( normalizeRequestId ( dep ) , importer )
233- return [ dep , resolved ?. id ]
234- }
237+ /** @internal */
238+ async directRequest ( id : string , fsPath : string , _callstack : string [ ] ) {
239+ const moduleId = normalizeModuleId ( fsPath )
240+ const callstack = [ ..._callstack , moduleId ]
235241
236- return [ dep , undefined ]
237- }
242+ const mod = this . moduleCache . get ( fsPath )
238243
239- const [ dep , resolvedId ] = await resolveId ( id , 2 )
244+ const request = async ( dep : string ) => {
245+ const [ id , depFsPath ] = await this . resolveUrl ( dep , fsPath )
246+ return this . dependencyRequest ( id , depFsPath , callstack )
247+ }
240248
241249 const requestStubs = this . options . requestStubs || DEFAULT_REQUEST_STUBS
242250 if ( id in requestStubs )
243251 return requestStubs [ id ]
244252
245253 // eslint-disable-next-line prefer-const
246- let { code : transformed , externalize } = await this . options . fetchModule ( resolvedId || dep )
247-
248- // in case we resolved fsPath incorrectly, Vite will return the correct file path
249- // in that case we need to update cache, so we don't have the same module as different exports
250- // but we ignore fsPath that has custom query, because it might need to be different
251- if ( resolvedId && ! fsPath . includes ( '?' ) && fsPath !== resolvedId ) {
252- if ( this . moduleCache . has ( resolvedId ) ) {
253- mod = this . moduleCache . get ( resolvedId )
254- this . moduleCache . set ( fsPath , mod )
255- if ( mod . promise )
256- return mod . promise
257- if ( mod . exports )
258- return mod . exports
259- }
260- else {
261- this . moduleCache . set ( resolvedId , mod )
262- }
263- }
254+ let { code : transformed , externalize } = await this . options . fetchModule ( id )
264255
265256 if ( externalize ) {
266257 debugNative ( externalize )
@@ -270,13 +261,12 @@ export class ViteNodeRunner {
270261 }
271262
272263 if ( transformed == null )
273- throw new Error ( `[vite-node] Failed to load ${ id } ` )
274-
275- const file = cleanUrl ( resolvedId || fsPath )
264+ throw new Error ( `[vite-node] Failed to load "${ id } " imported from ${ callstack [ callstack . length - 2 ] } ` )
276265
266+ const modulePath = cleanUrl ( moduleId )
277267 // disambiguate the `<UNIT>:/` on windows: see nodejs/node#31710
278- const url = pathToFileURL ( file ) . href
279- const meta = { url }
268+ const href = pathToFileURL ( modulePath ) . href
269+ const meta = { url : href }
280270 const exports = Object . create ( null )
281271 Object . defineProperty ( exports , Symbol . toStringTag , {
282272 value : 'Module' ,
@@ -305,7 +295,7 @@ export class ViteNodeRunner {
305295 } )
306296
307297 Object . assign ( mod , { code : transformed , exports } )
308- const __filename = fileURLToPath ( url )
298+ const __filename = fileURLToPath ( href )
309299 const moduleProxy = {
310300 set exports ( value ) {
311301 exportAll ( cjsExports , value )
@@ -339,10 +329,9 @@ export class ViteNodeRunner {
339329 __vite_ssr_exports__ : exports ,
340330 __vite_ssr_exportAll__ : ( obj : any ) => exportAll ( exports , obj ) ,
341331 __vite_ssr_import_meta__ : meta ,
342- __vitest_resolve_id__ : resolveId ,
343332
344333 // cjs compact
345- require : createRequire ( url ) ,
334+ require : createRequire ( href ) ,
346335 exports : cjsExports ,
347336 module : moduleProxy ,
348337 __filename,
@@ -373,13 +362,6 @@ export class ViteNodeRunner {
373362 return context
374363 }
375364
376- shouldResolveId ( dep : string ) {
377- if ( isNodeBuiltin ( dep ) || dep in ( this . options . requestStubs || DEFAULT_REQUEST_STUBS ) || dep . startsWith ( '/@vite' ) )
378- return false
379-
380- return ! isAbsolute ( dep ) || ! extname ( dep )
381- }
382-
383365 /**
384366 * Define if a module should be interop-ed
385367 * This function mostly for the ability to override by subclass
0 commit comments