1
+ import { receiveMessageOnPort } from 'node:worker_threads' ;
1
2
const mockedModuleExports = new Map ( ) ;
2
3
let currentMockVersion = 0 ;
3
4
4
- // This loader enables code running on the application thread to
5
+ // These hooks enable code running on the application thread to
5
6
// swap module resolution results for mocking purposes. It uses this instead
6
7
// of import.meta so that CommonJS can still use the functionality.
7
8
//
@@ -33,18 +34,40 @@ let currentMockVersion = 0;
33
34
// assert(namespace1 === namespace2);
34
35
// ```
35
36
36
- /** @type {string } */
37
- let mainImportURL ;
37
+ /**
38
+ * @param param0 message from the application context
39
+ */
40
+ function onPreloadPortMessage ( {
41
+ mockVersion, resolved, exports
42
+ } ) {
43
+ currentMockVersion = mockVersion ;
44
+ mockedModuleExports . set ( resolved , exports ) ;
45
+ }
46
+
47
+ /** @type {URL['href'] } */
48
+ let mainImportURL
49
+ /** @type {MessagePort } */
50
+ let preloadPort ;
38
51
export async function initialize ( data ) {
39
- mainImportURL = data . mainImportURL ;
40
- data . port . on ( 'message' , ( { mockVersion, resolved, exports } ) => {
41
- currentMockVersion = mockVersion ;
42
- mockedModuleExports . set ( resolved , exports ) ;
43
- } ) ;
52
+ ( { mainImportURL, port : preloadPort } = data ) ;
53
+
54
+ data . port . on ( 'message' , onPreloadPortMessage ) ;
55
+ }
56
+
57
+ /**
58
+ * FIXME: this is a hack to workaround loaders being
59
+ * single threaded for now, just ensures that the MessagePort drains
60
+ */
61
+ function doDrainPort ( ) {
62
+ let msg ;
63
+ while ( msg = receiveMessageOnPort ( preloadPort ) ) {
64
+ onPreloadPortMessage ( msg . message ) ;
65
+ }
44
66
}
45
67
46
68
// Rewrites node: loading to mock-facade: so that it can be intercepted
47
69
export async function resolve ( specifier , context , defaultResolve ) {
70
+ doDrainPort ( ) ;
48
71
const def = await defaultResolve ( specifier , context ) ;
49
72
if ( context . parentURL ?. startsWith ( 'mock-facade:' ) ) {
50
73
// Do nothing, let it get the "real" module
@@ -61,17 +84,17 @@ export async function resolve(specifier, context, defaultResolve) {
61
84
}
62
85
63
86
export async function load ( url , context , defaultLoad ) {
87
+ doDrainPort ( ) ;
64
88
/**
65
89
* Mocked fake module, not going to be handled in default way so it
66
90
* generates the source text, then short circuits
67
91
*/
68
92
if ( url . startsWith ( 'mock-facade:' ) ) {
69
- let [ _proto , _version , encodedTargetURL ] = url . split ( ':' ) ;
70
- let source = generateModule ( encodedTargetURL ) ;
93
+ const encodedTargetURL = url . slice ( url . lastIndexOf ( ':' ) + 1 ) ;
71
94
return {
72
95
shortCircuit : true ,
73
- source,
74
- format : 'module'
96
+ source : generateModule ( encodedTargetURL ) ,
97
+ format : 'module' ,
75
98
} ;
76
99
}
77
100
return defaultLoad ( url , context ) ;
@@ -89,19 +112,19 @@ function generateModule(encodedTargetURL) {
89
112
let body = [
90
113
`import { mockedModules } from ${ JSON . stringify ( mainImportURL ) } ;` ,
91
114
'export {};' ,
92
- 'let mapping = {__proto__: null};'
115
+ 'let mapping = {__proto__: null};' ,
116
+ `const mock = mockedModules.get(${ JSON . stringify ( encodedTargetURL ) } );` ,
93
117
] ;
94
118
for ( const [ i , name ] of Object . entries ( exports ) ) {
95
119
let key = JSON . stringify ( name ) ;
96
- body . push ( `import.meta.mock = mockedModules.get(${ JSON . stringify ( encodedTargetURL ) } );` ) ;
97
- body . push ( `var _${ i } = import.meta.mock.namespace[${ key } ];` ) ;
120
+ body . push ( `var _${ i } = mock.namespace[${ key } ];` ) ;
98
121
body . push ( `Object.defineProperty(mapping, ${ key } , { enumerable: true, set(v) {_${ i } = v;}, get() {return _${ i } ;} });` ) ;
99
122
body . push ( `export {_${ i } as ${ name } };` ) ;
100
123
}
101
- body . push ( `import.meta. mock.listeners.push(${
124
+ body . push ( `mock.listeners.push(${
102
125
( ) => {
103
126
for ( var k in mapping ) {
104
- mapping [ k ] = import . meta . mock . namespace [ k ] ;
127
+ mapping [ k ] = mock . namespace [ k ] ;
105
128
}
106
129
}
107
130
} );`) ;
0 commit comments