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

esm: refactor dynamic modules #9

Merged
merged 1 commit into from
Nov 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
};
Expand Down
76 changes: 32 additions & 44 deletions lib/internal/modules/esm/create_dynamic_module.js
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -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,
};
};
Expand Down
7 changes: 4 additions & 3 deletions lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
Expand Down