diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/internal/bootstrap/loaders.js | 92 | ||||
-rw-r--r-- | lib/internal/modules/cjs/loader.js | 8 | ||||
-rw-r--r-- | lib/internal/modules/esm/translators.js | 10 |
3 files changed, 47 insertions, 63 deletions
diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index cc1157a557..dbc21a9697 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -151,6 +151,7 @@ function NativeModule(id) { this.id = id; this.exports = {}; this.reflect = undefined; + this.esmFacade = undefined; this.exportKeys = undefined; this.loaded = false; this.loading = false; @@ -211,15 +212,19 @@ function requireWithFallbackInDeps(request) { } // This is exposed for public loaders -NativeModule.prototype.compileForPublicLoader = function(needToProxify) { +NativeModule.prototype.compileForPublicLoader = function(needToSyncExports) { if (!this.canBeRequiredByUsers) { // No code because this is an assertion against bugs // eslint-disable-next-line no-restricted-syntax throw new Error(`Should not compile ${this.id} for public use`); } this.compile(); - if (needToProxify && !this.exportKeys) { - this.proxifyExports(); + if (needToSyncExports) { + if (!this.exportKeys) { + this.exportKeys = Object.keys(this.exports); + } + this.getESMFacade(); + this.syncExports(); } return this.exports; }; @@ -230,61 +235,38 @@ const getOwn = (target, property, receiver) => { undefined; }; +NativeModule.prototype.getURL = function() { + return `node:${this.id}`; +}; + +NativeModule.prototype.getESMFacade = function() { + if (this.esmFacade) return this.esmFacade; + const createDynamicModule = nativeModuleRequire( + 'internal/modules/esm/create_dynamic_module'); + const url = this.getURL(); + return this.esmFacade = createDynamicModule( + [], [...this.exportKeys, 'default'], url, (reflect) => { + this.reflect = reflect; + this.syncExports(); + reflect.exports.default.set(this.exports); + }); +}; + // Provide named exports for all builtin libraries so that the libraries // may be imported in a nicer way for ESM users. The default export is left -// as the entire namespace (module.exports) and wrapped in a proxy such -// that APMs and other behavior are still left intact. -NativeModule.prototype.proxifyExports = function() { - this.exportKeys = Object.keys(this.exports); - - const update = (property, value) => { - if (this.reflect !== undefined && - ObjectPrototype.hasOwnProperty(this.reflect.exports, property)) - this.reflect.exports[property].set(value); - }; - - const handler = { - __proto__: null, - defineProperty: (target, prop, descriptor) => { - // Use `Object.defineProperty` instead of `Reflect.defineProperty` - // to throw the appropriate error if something goes wrong. - Object.defineProperty(target, prop, descriptor); - if (typeof descriptor.get === 'function' && - !Reflect.has(handler, 'get')) { - handler.get = (target, prop, receiver) => { - const value = Reflect.get(target, prop, receiver); - if (ObjectPrototype.hasOwnProperty(target, prop)) - update(prop, value); - return value; - }; - } - update(prop, getOwn(target, prop)); - return true; - }, - deleteProperty: (target, prop) => { - if (Reflect.deleteProperty(target, prop)) { - update(prop, undefined); - return true; - } - return false; - }, - set: (target, prop, value, receiver) => { - const descriptor = Reflect.getOwnPropertyDescriptor(target, prop); - if (Reflect.set(target, prop, value, receiver)) { - if (descriptor && typeof descriptor.set === 'function') { - for (const key of this.exportKeys) { - update(key, getOwn(target, key, receiver)); - } - } else { - update(prop, getOwn(target, prop, receiver)); - } - return true; - } - return false; +// as the entire namespace (module.exports) and updates when this function is +// called so that APMs and other behavior are supported. +NativeModule.prototype.syncExports = function() { + const names = this.exportKeys; + if (this.reflect) { + for (let i = 0; i < names.length; i++) { + const exportName = names[i]; + if (exportName === 'default') continue; + this.reflect.exports[exportName].set( + getOwn(this.exports, exportName, this.exports) + ); } - }; - - this.exports = new Proxy(this.exports, handler); + } }; NativeModule.prototype.compile = function() { diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 9bee9130d2..862b149e5a 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -1135,6 +1135,14 @@ Module._preloadModules = function(requests) { parent.require(requests[n]); }; +Module.syncBuiltinESMExports = function syncBuiltinESMExports() { + for (const mod of NativeModule.map.values()) { + if (mod.canBeRequiredByUsers) { + mod.syncExports(); + } + } +}; + // Backwards compatibility Module.Module = Module; diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 056bf64bf5..e8eddcfd21 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -128,14 +128,8 @@ translators.set('builtin', async function builtinStrategy(url) { if (!module) { throw new ERR_UNKNOWN_BUILTIN_MODULE(id); } - return createDynamicModule( - [], [...module.exportKeys, 'default'], url, (reflect) => { - debug(`Loading BuiltinModule ${url}`); - module.reflect = reflect; - for (const key of module.exportKeys) - reflect.exports[key].set(module.exports[key]); - reflect.exports.default.set(module.exports); - }); + debug(`Loading BuiltinModule ${url}`); + return module.getESMFacade(); }); // Strategy for loading a JSON file |