From 879c0f1f3eee4c112e4e2ea0159eca76fea9f9dd Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sat, 3 Nov 2018 14:26:32 +0800 Subject: [PATCH] lib: move module exports proxy into a separate method Also added the comment in f074612b7 to make NativeModule.prototype.compile() more readable. PR-URL: https://github.com/nodejs/node/pull/24057 Reviewed-By: Anna Henningsen Reviewed-By: Gus Caplan Reviewed-By: Refael Ackermann --- lib/internal/bootstrap/loaders.js | 110 ++++++++++++++++-------------- 1 file changed, 59 insertions(+), 51 deletions(-) diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index aceb15cc63fc69..cd7a566fb1f9a3 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -235,6 +235,64 @@ undefined; }; + // 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 = ObjectKeys(this.exports); + + const update = (property, value) => { + if (this.reflect !== undefined && + ReflectApply(ObjectHasOwnProperty, + 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. + ObjectDefineProperty(target, prop, descriptor); + if (typeof descriptor.get === 'function' && + !ReflectHas(handler, 'get')) { + handler.get = (target, prop, receiver) => { + const value = ReflectGet(target, prop, receiver); + if (ReflectApply(ObjectHasOwnProperty, target, [prop])) + update(prop, value); + return value; + }; + } + update(prop, getOwn(target, prop)); + return true; + }, + deleteProperty: (target, prop) => { + if (ReflectDeleteProperty(target, prop)) { + update(prop, undefined); + return true; + } + return false; + }, + set: (target, prop, value, receiver) => { + const descriptor = ReflectGetOwnPropertyDescriptor(target, prop); + if (ReflectSet(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; + } + }; + + this.exports = new Proxy(this.exports, handler); + }; + NativeModule.prototype.compile = function() { const id = this.id; let source = NativeModule.getSource(id); @@ -299,57 +357,7 @@ fn(this.exports, requireFn, this, process, internalBinding); if (config.experimentalModules && !NativeModule.isInternal(this.id)) { - this.exportKeys = ObjectKeys(this.exports); - - const update = (property, value) => { - if (this.reflect !== undefined && - ReflectApply(ObjectHasOwnProperty, - 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. - ObjectDefineProperty(target, prop, descriptor); - if (typeof descriptor.get === 'function' && - !ReflectHas(handler, 'get')) { - handler.get = (target, prop, receiver) => { - const value = ReflectGet(target, prop, receiver); - if (ReflectApply(ObjectHasOwnProperty, target, [prop])) - update(prop, value); - return value; - }; - } - update(prop, getOwn(target, prop)); - return true; - }, - deleteProperty: (target, prop) => { - if (ReflectDeleteProperty(target, prop)) { - update(prop, undefined); - return true; - } - return false; - }, - set: (target, prop, value, receiver) => { - const descriptor = ReflectGetOwnPropertyDescriptor(target, prop); - if (ReflectSet(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; - } - }; - - this.exports = new Proxy(this.exports, handler); + this.proxifyExports(); } this.loaded = true;