2

While going through the source of require() in the GitHub repository for Node.js, I am surprised and confused by one thing:

The file loader.js that actually defines the require() logic, uses require() calls in itself.

How is this possible?

Is there some other code for the require() calls used in the internals of Node.js, for e.g. all the require() calls used in loader.js file.

I know that all require() calls in a Node.js program that I write in a given editor, on my machine, are resolved using the Module.prototype.require method declared in loader.js.

1 Answer 1

2

It seems like the actual base require is defined here, in /internal/bootstrap/loaders.js. This line makes use of [compileFunction][3] in /lib/vm.js. That again uses _compileFunction which is defined as such:

const {
  ContextifyScript,
  MicrotaskQueue,
  makeContext,
  isContext: _isContext,
  constants,
  compileFunction: _compileFunction,
  measureMemory: _measureMemory,
} = internalBinding('contextify');

Which, if we go back to /internal/bootstrap/loaders.js, is defined as such:

let internalBinding;
{
  const bindingObj = ObjectCreate(null);
  // eslint-disable-next-line no-global-assign
  internalBinding = function internalBinding(module) {
    let mod = bindingObj[module];
    if (typeof mod !== 'object') {
      mod = bindingObj[module] = getInternalBinding(module);
      ArrayPrototypePush(moduleLoadList, `Internal Binding ${module}`);
    }
    return mod;
  };
}

And getInternalBinding we find at the top of that file, in this comment:

// This file is compiled as if it's wrapped in a function with arguments
// passed by node::RunBootstrapping()
/* global process, getLinkedBinding, getInternalBinding, primordials */

Which brings an end to our tour here. So yes, there's still some code between the require() defined in loader.js and the actual C binding. As for what happens in C-land, I'm not sure myself.

Sign up to request clarification or add additional context in comments.

7 Comments

I wonder then what's the purpose of creating a new require() function, when there already is one defined?
Is the new require(), defined in loader.js, a bit more flexible than the one defined in the file node.js? If yes, then how?
Yes. The one in loaders.js seems only capable of requiring native modules. The one in loader.js actually sets up the whole deal of loading (non-native) modules from files, load modules relative to the current module, wrap module code in the (function (exports, require, ...) wrapper (therefore providing it its own require that's relative to the module's path), ...
Any ideas why the Node team didn't implement it just once as a full-fledge function, rather than first create a minimal function and then a more robust function?
Not sure, but I'd say they use layering both for maintenance and clarity. You have getInternalBinding, on top of that loaders.js which wraps requiring native modules using bindings, then loader.js which actually implements the whole CJS module/require system. Mind that we're talking about /internal/modules/cjs/loader.js. Mind that there's also /internal/modules/esm/loader.js for ESM modules.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.