'How require work under the hood in NodeJS?

I try to understand how bootstrapping of nodeJS works, but I am stacked with the function require

  1. First use of require inside internal/bootstrap/node.js (See picture below)
  2. require passed to this file in src/node.cc as native_module_require
  3. node.cc take require from internal/bootstrap/loaders.js (which executed before step 1)
  4. internal/bootstrap/loaders.js use internalBinding, which use getInternalBinding
  5. getInternalBinding create from ...
  6. src/node_binding.cc, looks a little bit complicated, but my case ("native_module" from step 4) is findModule(modlist_internal...
  7. modlist_internal saved in node_module_register
  8. which is called from napi_module_register
  9. which is called from NAPI_MODULE
  10. but I cannot find where NAPI_MODULE is used (except for test and bench)

code blocks

I use 16.14.0 LTS version of nodeJS from GitHub

What I am trying to do? Nothing special, just curiosity, I also study the source code of the old project, which can run node inside the browser https://github.com/olydis/node-in-browser, but it use old version of nodeJS (with different require), and the project is not updated few years. Also, I am wondering, how stackblitz.com launch a modern version of nodeJS inside the browser.

P.S. there is also folder lib\internal\modules\ which is somehow related to require and import but I don't think its used in bootstrapping process, maybe a little bit later

P.P.S. I know only javaScript, so I can miss something important in C++ source code



Solution 1:[1]

In the .data section of the node executable there are C++ strings that contain native js sources. In the .text section of the node executable are executable code fragments compiled from those strings. V8 maintains the bindings between the native js sources and the executable code fragments through mappings inside the global object of the V8 instance's isolate, and node sets up the V8 isolate with the correct mappings/bindings during initialization. Require is one of the native js sources.

Further js code is converted into executable code and data by node through V8. Your program, which calls require, is such js code. Since require is a native js module, a binding to executable code exists, so V8 knows which address to use when compiling the call. The implementation of require has logic to find out whether its argument is a native module or not, as there's different logic for importing native vs non-native modules.

So a call to require works by getting compiled to a call to a pre-compiled function that is part of the node executable that V8 knows about thanks to node's set up of V8.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1