Skip to content

Commit d1bedb7

Browse files
committed
do not mutate import.meta, trailing commas, add doDrainPort back
1 parent 844fe45 commit d1bedb7

File tree

3 files changed

+44
-22
lines changed

3 files changed

+44
-22
lines changed

test/es-module/test-esm-loader-mock.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Flags: --import ./test/fixtures/es-module-loaders/mock.mjs
1+
import '../common/index.mjs';
22
import assert from 'node:assert/strict';
33
import { mock } from '../fixtures/es-module-loaders/mock.mjs';
44

test/fixtures/es-module-loaders/mock-loader.mjs

+40-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { receiveMessageOnPort } from 'node:worker_threads';
12
const mockedModuleExports = new Map();
23
let currentMockVersion = 0;
34

4-
// This loader enables code running on the application thread to
5+
// These hooks enable code running on the application thread to
56
// swap module resolution results for mocking purposes. It uses this instead
67
// of import.meta so that CommonJS can still use the functionality.
78
//
@@ -33,18 +34,40 @@ let currentMockVersion = 0;
3334
// assert(namespace1 === namespace2);
3435
// ```
3536

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;
3851
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+
}
4466
}
4567

4668
// Rewrites node: loading to mock-facade: so that it can be intercepted
4769
export async function resolve(specifier, context, defaultResolve) {
70+
doDrainPort();
4871
const def = await defaultResolve(specifier, context);
4972
if (context.parentURL?.startsWith('mock-facade:')) {
5073
// Do nothing, let it get the "real" module
@@ -61,17 +84,17 @@ export async function resolve(specifier, context, defaultResolve) {
6184
}
6285

6386
export async function load(url, context, defaultLoad) {
87+
doDrainPort();
6488
/**
6589
* Mocked fake module, not going to be handled in default way so it
6690
* generates the source text, then short circuits
6791
*/
6892
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);
7194
return {
7295
shortCircuit: true,
73-
source,
74-
format: 'module'
96+
source: generateModule(encodedTargetURL),
97+
format: 'module',
7598
};
7699
}
77100
return defaultLoad(url, context);
@@ -89,19 +112,19 @@ function generateModule(encodedTargetURL) {
89112
let body = [
90113
`import { mockedModules } from ${JSON.stringify(mainImportURL)};`,
91114
'export {};',
92-
'let mapping = {__proto__: null};'
115+
'let mapping = {__proto__: null};',
116+
`const mock = mockedModules.get(${JSON.stringify(encodedTargetURL)});`,
93117
];
94118
for (const [i, name] of Object.entries(exports)) {
95119
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}];`);
98121
body.push(`Object.defineProperty(mapping, ${key}, { enumerable: true, set(v) {_${i} = v;}, get() {return _${i};} });`);
99122
body.push(`export {_${i} as ${name}};`);
100123
}
101-
body.push(`import.meta.mock.listeners.push(${
124+
body.push(`mock.listeners.push(${
102125
() => {
103126
for (var k in mapping) {
104-
mapping[k] = import.meta.mock.namespace[k];
127+
mapping[k] = mock.namespace[k];
105128
}
106129
}
107130
});`);

test/fixtures/es-module-loaders/mock.mjs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import * as fixtures from '../../common/fixtures.mjs';
21
import { register } from 'node:module';
32
import { MessageChannel } from 'node:worker_threads';
43

54

65
const { port1, port2 } = new MessageChannel();
76

8-
register(fixtures.fileURL('es-module-loaders/mock-loader.mjs'), {
7+
register('./mock-loader.mjs', import.meta.url, {
98
data: {
109
port: port2,
1110
mainImportURL: import.meta.url,
@@ -53,12 +52,12 @@ export function mock(resolved, replacementProperties) {
5352
/* noop */
5453
}
5554
}
56-
}
55+
},
5756
});
5857
}
5958
mockedModules.set(encodeURIComponent(resolved), {
6059
namespace,
61-
listeners
60+
listeners,
6261
});
6362
mockVersion++;
6463
// Inform the loader that the `resolved` URL should now use the specific

0 commit comments

Comments
 (0)