// This file creates the internal module & binding loaders used by built-in // modules. In contrast, user land modules are loaded using // lib/internal/modules/cjs/loader.js (CommonJS Modules) or // lib/internal/modules/esm/* (ES Modules). // // This file is compiled and run by node.cc before bootstrap/node.js // was called, therefore the loaders are bootstraped before we start to // actually bootstrap Node.js. It creates the following objects: // // C++ binding loaders: // - process.binding(): the legacy C++ binding loader, accessible from user land // because it is an object attached to the global process object. // These C++ bindings are created using NODE_BUILTIN_MODULE_CONTEXT_AWARE() // and have their nm_flags set to NM_F_BUILTIN. We do not make any guarantees // about the stability of these bindings, but still have to take care of // compatibility issues caused by them from time to time. // - process._linkedBinding(): intended to be used by embedders to add // additional C++ bindings in their applications. These C++ bindings // can be created using NODE_MODULE_CONTEXT_AWARE_CPP() with the flag // NM_F_LINKED. // - internalBinding(): the private internal C++ binding loader, inaccessible // from user land because they are only available from NativeModule.require(). // These C++ bindings are created using NODE_MODULE_CONTEXT_AWARE_INTERNAL() // and have their nm_flags set to NM_F_INTERNAL. // // Internal JavaScript module loader: // - NativeModule: a minimal module system used to load the JavaScript core // modules found in lib/**/*.js and deps/**/*.js. All core modules are // compiled into the node binary via node_javascript.cc generated by js2c.py, // so they can be loaded faster without the cost of I/O. This class makes the // lib/internal/*, deps/internal/* modules and internalBinding() available by // default to core modules, and lets the core modules require itself via // require('internal/bootstrap/loaders') even when this file is not written in // CommonJS style. // // Other objects: // - process.moduleLoadList: an array recording the bindings and the modules // loaded in the process and the order in which they are loaded. 'use strict'; // This file is compiled as if it's wrapped in a function with arguments // passed by node::RunBootstrapping() /* global process, getLinkedBinding, getInternalBinding */ /* global experimentalModules, exposeInternals, primordials */ const { Reflect, Object, ObjectPrototype, SafeSet } = primordials; // Set up process.moduleLoadList. const moduleLoadList = []; Object.defineProperty(process, 'moduleLoadList', { value: moduleLoadList, configurable: true, enumerable: true, writable: false }); // internalBindingWhitelist contains the name of internalBinding modules // that are whitelisted for access via process.binding()... This is used // to provide a transition path for modules that are being moved over to // internalBinding. const internalBindingWhitelist = new SafeSet([ 'async_wrap', 'buffer', 'cares_wrap', 'config', 'constants', 'contextify', 'crypto', 'fs', 'fs_event_wrap', 'http_parser', 'icu', 'inspector', 'js_stream', 'natives', 'os', 'pipe_wrap', 'process_wrap', 'signal_wrap', 'spawn_sync', 'stream_wrap', 'tcp_wrap', 'tls_wrap', 'tty_wrap', 'udp_wrap', 'url', 'util', 'uv', 'v8', 'zlib' ]); // Set up process.binding() and process._linkedBinding(). { const bindingObj = Object.create(null); process.binding = function binding(module) { module = String(module); // Deprecated specific process.binding() modules, but not all, allow // selective fallback to internalBinding for the deprecated ones. if (internalBindingWhitelist.has(module)) { return internalBinding(module); } // eslint-disable-next-line no-restricted-syntax throw new Error(`No such module: ${module}`); }; process._linkedBinding = function _linkedBinding(module) { module = String(module); let mod = bindingObj[module]; if (typeof mod !== 'object') mod = bindingObj[module] = getLinkedBinding(module); return mod; }; } // Set up internalBinding() in the closure. let internalBinding; { const bindingObj = Object.create(null); internalBinding = function internalBinding(module) { let mod = bindingObj[module]; if (typeof mod !== 'object') { mod = bindingObj[module] = getInternalBinding(module); moduleLoadList.push(`Internal Binding ${module}`); } return mod; }; } // Create this WeakMap in js-land because V8 has no C++ API for WeakMap. internalBinding('module_wrap').callbackMap = new WeakMap(); // Think of this as module.exports in this file even though it is not // written in CommonJS style. const loaderExports = { internalBinding, NativeModule, require: nativeModuleRequire }; const loaderId = 'internal/bootstrap/loaders'; // Set up NativeModule. function NativeModule(id) { this.filename = `${id}.js`; this.id = id; this.exports = {}; this.reflect = undefined; this.exportKeys = undefined; this.loaded = false; this.loading = false; if (id === loaderId) { // Do not expose this to user land even with --expose-internals. this.canBeRequiredByUsers = false; } else if (id.startsWith('internal/')) { this.canBeRequiredByUsers = exposeInternals; } else { this.canBeRequiredByUsers = true; } } const { moduleIds, compileFunction } = internalBinding('native_module'); NativeModule.map = new Map(); for (var i = 0; i < moduleIds.length; ++i) { const id = moduleIds[i]; const mod = new NativeModule(id); NativeModule.map.set(id, mod); } function nativeModuleRequire(id) { if (id === loaderId) { return loaderExports; } const mod = NativeModule.map.get(id); if (!mod) { // Model the error off the internal/errors.js model, but // do not use that module given that it could actually be // the one causing the error if there's a bug in Node.js. // eslint-disable-next-line no-restricted-syntax const err = new Error(`No such built-in module: ${id}`); err.code = 'ERR_UNKNOWN_BUILTIN_MODULE'; err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]'; throw err; } if (mod.loaded || mod.loading) { return mod.exports; } moduleLoadList.push(`NativeModule ${id}`); mod.compile(); return mod.exports; } NativeModule.require = nativeModuleRequire; NativeModule.exists = function(id) { return NativeModule.map.has(id); }; NativeModule.canBeRequiredByUsers = function(id) { const mod = NativeModule.map.get(id); return mod && mod.canBeRequiredByUsers; }; // Allow internal modules from dependencies to require // other modules from dependencies by providing fallbacks. NativeModule.requireWithFallbackInDeps = function(request) { if (!NativeModule.map.has(request)) { request = `internal/deps/${request}`; } return NativeModule.require(request); }; const getOwn = (target, property, receiver) => { return Reflect.apply(ObjectPrototype.hasOwnProperty, target, [property]) ? Reflect.get(target, property, receiver) : 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 = Object.keys(this.exports); const update = (property, value) => { if (this.reflect !== undefined && Reflect.apply(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 (Reflect.apply(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; } }; this.exports = new Proxy(this.exports, handler); }; NativeModule.prototype.compile = function() { const id = this.id; this.loading = true; try { const requireFn = this.id.startsWith('internal/deps/') ? NativeModule.requireWithFallbackInDeps : NativeModule.require; const fn = compileFunction(id); fn(this.exports, requireFn, this, process, internalBinding, primordials); if (experimentalModules && this.canBeRequiredByUsers) { this.proxifyExports(); } this.loaded = true; } finally { this.loading = false; } }; // Coverage must be turned on early, so that we can collect // it for Node.js' own internal libraries. if (process.env.NODE_V8_COVERAGE) { if (internalBinding('config').hasInspector) { const coverage = NativeModule.require('internal/coverage-gen/with_profiler'); // Inform the profiler to start collecting coverage coverage.startCoverageCollection(); } else { process._rawDebug('NODE_V8_COVERAGE cannot be used without inspector'); } } // This will be passed to internal/bootstrap/node.js. return loaderExports;