|
1 | 1 | 'use strict';
|
2 | 2 |
|
3 |
| -const { ModuleWrap } = internalBinding('module_wrap'); |
| 3 | +const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); |
4 | 4 | const debug = require('util').debuglog('esm');
|
5 | 5 | const ArrayJoin = Function.call.bind(Array.prototype.join);
|
6 | 6 | const ArrayMap = Function.call.bind(Array.prototype.map);
|
7 | 7 |
|
| 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 | + |
8 | 14 | const createDynamicModule = (exports, url = '', evaluate) => {
|
9 | 15 | debug(
|
10 | 16 | `creating ESM facade for ${url} with exports: ${ArrayJoin(exports, ', ')}`
|
11 | 17 | );
|
12 | 18 | 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 | +};`; |
30 | 36 | }
|
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 | + |
55 | 58 | return {
|
56 |
| - module, |
| 59 | + module: m, |
57 | 60 | reflect,
|
58 | 61 | };
|
59 | 62 | };
|
|
0 commit comments