Skip to content
This repository was archived by the owner on Apr 16, 2020. It is now read-only.

Commit 285493f

Browse files
committed
esm: refactor dynamic modules
1 parent 47aac7c commit 285493f

File tree

3 files changed

+61
-59
lines changed

3 files changed

+61
-59
lines changed

lib/internal/modules/cjs/loader.js

+11-13
Original file line numberDiff line numberDiff line change
@@ -617,23 +617,21 @@ Module.prototype.load = function(filename) {
617617
if (experimentalModules) {
618618
if (asyncESM === undefined) lazyLoadESM();
619619
const ESMLoader = asyncESM.ESMLoader;
620-
const url = pathToFileURL(filename);
621-
const urlString = `${url}`;
622-
const exports = this.exports;
623-
if (ESMLoader.moduleMap.has(urlString) !== true) {
620+
const url = `${pathToFileURL(filename)}`;
621+
const module = ESMLoader.moduleMap.get(url);
622+
if (module !== undefined) {
623+
module.reflect.exports.default.set(this.exports);
624+
} else {
625+
const exports = this.exports;
624626
ESMLoader.moduleMap.set(
625-
urlString,
627+
url,
626628
new ModuleJob(ESMLoader, url, async () => {
627-
const ctx = createDynamicModule(
628-
['default'], url);
629-
ctx.reflect.exports.default.set(exports);
630-
return ctx;
629+
return createDynamicModule(
630+
['default'], url, (reflect) => {
631+
reflect.exports.default.set(exports);
632+
});
631633
})
632634
);
633-
} else {
634-
const job = ESMLoader.moduleMap.get(urlString);
635-
if (job.reflect)
636-
job.reflect.exports.default.set(exports);
637635
}
638636
}
639637
};

lib/internal/modules/esm/create_dynamic_module.js

+46-43
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,62 @@
11
'use strict';
22

3-
const { ModuleWrap } = internalBinding('module_wrap');
3+
const { ModuleWrap, callbackMap } = internalBinding('module_wrap');
44
const debug = require('util').debuglog('esm');
55
const ArrayJoin = Function.call.bind(Array.prototype.join);
66
const ArrayMap = Function.call.bind(Array.prototype.map);
77

8+
// This variable is used as the local binding for a default export from a
9+
// dynamic module. It's definitely a hack but it works quite
10+
// nicely for our purposes.
11+
const defaultName = '\u5343\u4e07\u4e0d\u8981\u7528\u8fd9\u4e2a\u53d8\u91cf' +
12+
'\u5426\u5219\u4f60\u4f1a\u88ab\u5f00\u9664';
13+
814
const createDynamicModule = (exports, url = '', evaluate) => {
915
debug(
1016
`creating ESM facade for ${url} with exports: ${ArrayJoin(exports, ', ')}`
1117
);
1218
const names = ArrayMap(exports, (name) => `${name}`);
13-
// Create two modules: One whose exports are get- and set-able ('reflective'),
14-
// and one which re-exports all of these but additionally may
15-
// run an executor function once everything is set up.
16-
const src = `
17-
export let executor;
18-
${ArrayJoin(ArrayMap(names, (name) => `export let $${name};`), '\n')}
19-
/* This function is implicitly returned as the module's completion value */
20-
(() => ({
21-
setExecutor: fn => executor = fn,
22-
reflect: {
23-
exports: { ${
24-
ArrayJoin(ArrayMap(names, (name) => `
25-
${name}: {
26-
get: () => $${name},
27-
set: v => $${name} = v
28-
}`), ', \n')}
29-
}
19+
20+
const source = `
21+
${ArrayJoin(ArrayMap(names, (name) => {
22+
if (name === 'default') {
23+
return `let ${defaultName};
24+
export { ${defaultName} as default };
25+
import.meta.exports.default = {
26+
get: () => ${defaultName},
27+
set: ($${defaultName}) => ${defaultName} = $${defaultName},
28+
};
29+
`;
30+
} else {
31+
return `export let ${name};
32+
import.meta.exports.${name} = {
33+
get: () => ${name},
34+
set: ($${name}) => ${name} = $${name},
35+
};`;
3036
}
31-
}));`;
32-
const reflectiveModule = new ModuleWrap(src, `cjs-facade:${url}`);
33-
reflectiveModule.instantiate();
34-
const { setExecutor, reflect } = reflectiveModule.evaluate(-1, false)();
35-
// public exposed ESM
36-
const reexports = `
37-
import {
38-
executor,
39-
${ArrayMap(names, (name) => `$${name}`)}
40-
} from "";
41-
export {
42-
${ArrayJoin(ArrayMap(names, (name) => `$${name} as ${name}`), ', ')}
43-
}
44-
if (typeof executor === "function") {
45-
// add await to this later if top level await comes along
46-
executor()
47-
}`;
48-
if (typeof evaluate === 'function') {
49-
setExecutor(() => evaluate(reflect));
50-
}
51-
const module = new ModuleWrap(reexports, `${url}`);
52-
module.link(async () => reflectiveModule);
53-
module.instantiate();
54-
reflect.namespace = module.namespace();
37+
}), '\n')}
38+
39+
import.meta.done();
40+
`;
41+
42+
const m = new ModuleWrap(source, `${url}`);
43+
m.link(() => 0);
44+
m.instantiate();
45+
46+
const reflect = {
47+
namespace: m.namespace,
48+
exports: {},
49+
};
50+
51+
callbackMap.set(m, {
52+
initializeImportMeta: (meta, wrap) => {
53+
meta.exports = reflect.exports;
54+
meta.done = () => evaluate(reflect);
55+
},
56+
});
57+
5558
return {
56-
module,
59+
module: m,
5760
reflect,
5861
};
5962
};

lib/internal/modules/esm/translators.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ translators.set('cjs', async (url, isMain) => {
5656
const module = CJSModule._cache[
5757
isWindows ? StringReplace(pathname, winSepRegEx, '\\') : pathname];
5858
if (module && module.loaded) {
59-
const ctx = createDynamicModule(['default'], url);
60-
ctx.reflect.exports.default.set(module.exports);
61-
return ctx;
59+
const exports = module.exports;
60+
return createDynamicModule(['default'], url, (reflect) => {
61+
reflect.exports.default.set(exports);
62+
});
6263
}
6364
return createDynamicModule(['default'], url, () => {
6465
debug(`Loading CJSModule ${url}`);

0 commit comments

Comments
 (0)