@@ -10,7 +10,8 @@ import {
10
10
ssrImportMetaKey ,
11
11
ssrDynamicImportKey
12
12
} from './ssrTransform'
13
- import { transformRequest } from '../server/transformRequest'
13
+ import { transformRequest , TransformResult } from '../server/transformRequest'
14
+ import { ModuleNode } from '../server/moduleGraph'
14
15
15
16
interface SSRContext {
16
17
global : NodeJS . Global
@@ -42,6 +43,14 @@ export async function ssrLoadModule(
42
43
// request to that module are simply waiting on the same promise.
43
44
const pending = pendingModules . get ( url )
44
45
if ( pending ) {
46
+ const { moduleGraph } = server
47
+ const mod = await moduleGraph . ensureEntryFromUrl ( url )
48
+ const transformResult = await transformModule ( mod , server )
49
+ const deps = ( transformResult . deps || [ ] ) . map ( ( d ) => unwrapId ( d ) )
50
+ const circularDep = urlStack . find ( ( u ) => deps . includes ( u ) )
51
+ if ( circularDep ) {
52
+ return { }
53
+ }
45
54
return pending
46
55
}
47
56
@@ -69,20 +78,16 @@ async function instantiateModule(
69
78
return mod . ssrModule
70
79
}
71
80
72
- const result =
73
- mod . ssrTransformResult ||
74
- ( await transformRequest ( url , server , { ssr : true } ) )
75
- if ( ! result ) {
76
- // TODO more info? is this even necessary?
77
- throw new Error ( `failed to load module for ssr: ${ url } ` )
78
- }
81
+ const result = await transformModule ( mod , server )
79
82
80
83
urlStack = urlStack . concat ( url )
81
84
82
85
const ssrModule = {
83
86
[ Symbol . toStringTag ] : 'Module'
84
87
}
85
88
Object . defineProperty ( ssrModule , '__esModule' , { value : true } )
89
+ // Set immediately so the module is available in case of circular dependencies.
90
+ mod . ssrModule = ssrModule
86
91
87
92
// Tolerate circular imports by ensuring the module can be
88
93
// referenced before it's been instantiated.
@@ -209,3 +214,24 @@ function resolve(id: string, importer: string | null, root: string) {
209
214
resolveCache . set ( key , resolved )
210
215
return resolved
211
216
}
217
+
218
+ const pendingTransforms = new Map < string , Promise < TransformResult | null > > ( )
219
+
220
+ async function transformModule ( mod : ModuleNode , server : ViteDevServer ) {
221
+ const url = mod . url
222
+ let transformResult = mod . ssrTransformResult
223
+ if ( ! transformResult ) {
224
+ let transformPromise = pendingTransforms . get ( url )
225
+ if ( ! transformPromise ) {
226
+ transformPromise = transformRequest ( url , server , { ssr : true } )
227
+ pendingTransforms . set ( url , transformPromise )
228
+ transformPromise . catch ( ( ) => { } ) . then ( ( ) => pendingTransforms . delete ( url ) )
229
+ }
230
+ transformResult = await transformPromise
231
+ }
232
+ if ( ! transformResult ) {
233
+ // TODO more info? is this even necessary?
234
+ throw new Error ( `failed to load module for ssr: ${ url } ` )
235
+ }
236
+ return transformResult
237
+ }
0 commit comments