11import { builtinModules , createRequire } from 'module'
22import { pathToFileURL } from 'url'
3- import { join , dirname , resolve } from 'path'
3+ import { dirname , resolve , relative } from 'path'
44import { createServer } from 'vite'
55import createDebug from 'debug'
66import minimist from 'minimist'
7- import { red , dim } from 'kolorist'
7+ import { red , dim , yellow } from 'kolorist'
88
99const argv = minimist ( process . argv . slice ( 2 ) , {
1010 alias : {
@@ -65,22 +65,43 @@ await server.close()
6565
6666// --- CLI END ---
6767
68- async function execute ( files , server ) {
69- const cache = { }
68+ function normalizeId ( id ) {
69+ // Virtual modules start with `\0`
70+ if ( id && id . startsWith ( '/@id/__x00__' ) )
71+ id = `\0${ id . slice ( '/@id/__x00__' . length ) } `
72+ if ( id && id . startsWith ( '/@id/' ) )
73+ id = id . slice ( '/@id/' . length )
74+ return id
75+ }
7076
71- async function request ( id ) {
72- // Virtual modules start with `\0`
73- if ( id && id . startsWith ( '/@id/__x00__' ) )
74- id = `\0${ id . slice ( '/@id/__x00__' . length ) } `
75- if ( id && id . startsWith ( '/@id/' ) )
76- id = id . slice ( '/@id/' . length )
77+ function toFilePath ( id ) {
78+ const absolute = id . startsWith ( '/@fs/' )
79+ ? id . slice ( 4 )
80+ : slash ( resolve ( server . config . root , id . slice ( 1 ) ) )
7781
78- if ( builtinModules . includes ( id ) )
79- return import ( id )
82+ return absolute
83+ }
84+
85+ async function execute ( files , server ) {
86+ const __pendingModules__ = new Map ( )
87+
88+ async function directRequest ( rawId , callstack ) {
89+ if ( builtinModules . includes ( rawId ) )
90+ return import ( rawId )
91+
92+ callstack = [ ...callstack , rawId ]
93+ const request = async ( dep ) => {
94+ if ( callstack . includes ( dep ) ) {
95+ throw new Error ( `${ red ( 'Circular dependency detected' ) } \nStack:\n${ [ ...callstack , dep ] . reverse ( ) . map ( ( i ) => {
96+ const path = relative ( server . config . root , toFilePath ( normalizeId ( i ) ) )
97+ return dim ( ' -> ' ) + ( i === dep ? yellow ( path ) : path )
98+ } ) . join ( '\n' ) } \n`)
99+ }
100+ return cachedRequest ( dep , callstack )
101+ }
80102
81- const absolute = id . startsWith ( '/@fs/' )
82- ? id . slice ( 3 )
83- : slash ( join ( server . config . root , id . slice ( 1 ) ) )
103+ const id = normalizeId ( rawId )
104+ const absolute = toFilePath ( id )
84105
85106 debugRequest ( absolute )
86107
@@ -89,7 +110,7 @@ async function execute(files, server) {
89110 ? `/${ absolute } `
90111 : absolute
91112
92- if ( id . includes ( '/node_modules/' ) )
113+ if ( absolute . includes ( '/node_modules/' ) )
93114 return import ( unifiedPath )
94115
95116 const result = await server . transformRequest ( id , { ssr : true } )
@@ -99,17 +120,16 @@ async function execute(files, server) {
99120 debugTransform ( id , result . code )
100121
101122 const url = pathToFileURL ( unifiedPath )
102-
103123 const exports = { }
104124
105125 const context = {
106126 require : createRequire ( url ) ,
107127 __filename : absolute ,
108128 __dirname : dirname ( absolute ) ,
109- __vite_ssr_import__ : cachedRequest ,
110- __vite_ssr_dynamic_import__ : cachedRequest ,
129+ __vite_ssr_import__ : request ,
130+ __vite_ssr_dynamic_import__ : request ,
111131 __vite_ssr_exports__ : exports ,
112- __vite_ssr_exportAll__ : obj => Object . assign ( exports , obj ) ,
132+ __vite_ssr_exportAll__ : obj => exportAll ( exports , obj ) ,
113133 __vite_ssr_import_meta__ : { url } ,
114134 }
115135
@@ -119,21 +139,37 @@ async function execute(files, server) {
119139 )
120140
121141 // prefetch deps
122- result . deps . forEach ( dep => cachedRequest ( dep ) )
142+ result . deps . forEach ( dep => request ( dep ) )
123143
124144 await fn ( ...Object . values ( context ) )
125145 return exports
126146 }
127147
128- function cachedRequest ( path ) {
129- if ( ! cache [ path ] )
130- cache [ path ] = request ( path )
131- return cache [ path ]
148+ function cachedRequest ( id , callstack ) {
149+ if ( ! __pendingModules__ [ id ] )
150+ __pendingModules__ [ id ] = directRequest ( id , callstack )
151+ return __pendingModules__ [ id ]
152+ }
153+
154+ function exportAll ( exports , sourceModule ) {
155+ // eslint-disable-next-line no-restricted-syntax
156+ for ( const key in sourceModule ) {
157+ if ( key !== 'default' ) {
158+ try {
159+ Object . defineProperty ( exports , key , {
160+ enumerable : true ,
161+ configurable : true ,
162+ get ( ) { return sourceModule [ key ] } ,
163+ } )
164+ }
165+ catch ( _err ) { }
166+ }
167+ }
132168 }
133169
134170 const result = [ ]
135171 for ( const file of files )
136- result . push ( await request ( `/@fs/${ slash ( resolve ( file ) ) } ` ) )
172+ result . push ( await cachedRequest ( `/@fs/${ slash ( resolve ( file ) ) } ` , [ ] ) )
137173 return result
138174}
139175
0 commit comments