From 60ec0641586fbad13b02293fa3d02676f2738627 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Mon, 8 Oct 2018 19:21:03 -0500 Subject: [PATCH] esm: refactor dynamic modules --- lib/internal/modules/cjs/loader.js | 24 +++--- .../modules/esm/create_dynamic_module.js | 76 ++++++++----------- lib/internal/modules/esm/translators.js | 7 +- 3 files changed, 47 insertions(+), 60 deletions(-) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 76a0ba9ee1..53989abc60 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -623,23 +623,21 @@ Module.prototype.load = function(filename) { if (experimentalModules) { if (asyncESM === undefined) lazyLoadESM(); const ESMLoader = asyncESM.ESMLoader; - const url = pathToFileURL(filename); - const urlString = `${url}`; - const exports = this.exports; - if (ESMLoader.moduleMap.has(urlString) !== true) { + const url = `${pathToFileURL(filename)}`; + const module = ESMLoader.moduleMap.get(url); + if (module !== undefined) { + module.reflect.exports.default.set(this.exports); + } else { + const exports = this.exports; ESMLoader.moduleMap.set( - urlString, + url, new ModuleJob(ESMLoader, url, async () => { - const ctx = createDynamicModule( - ['default'], url); - ctx.reflect.exports.default.set(exports); - return ctx; + return createDynamicModule( + ['default'], url, (reflect) => { + reflect.exports.default.set(exports); + }); }) ); - } else { - const job = ESMLoader.moduleMap.get(urlString); - if (job.reflect) - job.reflect.exports.default.set(exports); } } }; diff --git a/lib/internal/modules/esm/create_dynamic_module.js b/lib/internal/modules/esm/create_dynamic_module.js index 8e93a08502..6ac85973b8 100644 --- a/lib/internal/modules/esm/create_dynamic_module.js +++ b/lib/internal/modules/esm/create_dynamic_module.js @@ -1,6 +1,6 @@ 'use strict'; -const { ModuleWrap } = internalBinding('module_wrap'); +const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); const debug = require('util').debuglog('esm'); const ArrayJoin = Function.call.bind(Array.prototype.join); const ArrayMap = Function.call.bind(Array.prototype.map); @@ -10,50 +10,38 @@ const createDynamicModule = (exports, url = '', evaluate) => { `creating ESM facade for ${url} with exports: ${ArrayJoin(exports, ', ')}` ); const names = ArrayMap(exports, (name) => `${name}`); - // Create two modules: One whose exports are get- and set-able ('reflective'), - // and one which re-exports all of these but additionally may - // run an executor function once everything is set up. - const src = ` - export let executor; - ${ArrayJoin(ArrayMap(names, (name) => `export let $${name};`), '\n')} - /* This function is implicitly returned as the module's completion value */ - (() => ({ - setExecutor: fn => executor = fn, - reflect: { - exports: { ${ - ArrayJoin(ArrayMap(names, (name) => ` - ${name}: { - get: () => $${name}, - set: v => $${name} = v - }`), ', \n')} - } - } - }));`; - const reflectiveModule = new ModuleWrap(src, `cjs-facade:${url}`); - reflectiveModule.instantiate(); - const { setExecutor, reflect } = reflectiveModule.evaluate(-1, false)(); - // public exposed ESM - const reexports = ` - import { - executor, - ${ArrayMap(names, (name) => `$${name}`)} - } from ""; - export { - ${ArrayJoin(ArrayMap(names, (name) => `$${name} as ${name}`), ', ')} - } - if (typeof executor === "function") { - // add await to this later if top level await comes along - executor() - }`; - if (typeof evaluate === 'function') { - setExecutor(() => evaluate(reflect)); - } - const module = new ModuleWrap(reexports, `${url}`); - module.link(async () => reflectiveModule); - module.instantiate(); - reflect.namespace = module.namespace(); + + const source = ` +${ArrayJoin(ArrayMap(names, (name) => + `let $${name}; +export { $${name} as ${name} }; +import.meta.exports.${name} = { + get: () => $${name}, + set: (v) => $${name} = v, +};`), '\n') +} + +import.meta.done(); +`; + + const m = new ModuleWrap(source, `${url}`); + m.link(() => 0); + m.instantiate(); + + const reflect = { + namespace: m.namespace(), + exports: {}, + }; + + callbackMap.set(m, { + initializeImportMeta: (meta, wrap) => { + meta.exports = reflect.exports; + meta.done = () => evaluate(reflect); + }, + }); + return { - module, + module: m, reflect, }; }; diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 3da066ff24..216e504d3c 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -56,9 +56,10 @@ translators.set('cjs', async (url, isMain) => { const module = CJSModule._cache[ isWindows ? StringReplace(pathname, winSepRegEx, '\\') : pathname]; if (module && module.loaded) { - const ctx = createDynamicModule(['default'], url); - ctx.reflect.exports.default.set(module.exports); - return ctx; + const exports = module.exports; + return createDynamicModule(['default'], url, (reflect) => { + reflect.exports.default.set(exports); + }); } return createDynamicModule(['default'], url, () => { debug(`Loading CJSModule ${url}`);