Backend Development 17 min read

Exploring the Source Code of the Node.js Module System

This article delves into Node.js’s module system, explaining the CommonJS specification, how Node implements module loading, resolution, caching, and execution, and provides detailed analysis of core source code including Module constructor, require, _load, _resolveFilename, and file extension handling.

政采云技术
政采云技术
政采云技术
Exploring the Source Code of the Node.js Module System

Node.js enables front‑end engineers to work on the server, introducing a new runtime with its own module design. The article begins by introducing the CommonJS specification, which defines module.exports for exporting and require() for importing modules, along with the required global variables module , exports , and require .

Node’s Implementation of CommonJS

Node defines a module.require function and a global require to load modules. Each file is treated as an independent module, instantiated as a Module object with properties such as id , path , exports , parent , filename , loaded , and children .

function Module(id = "", parent) {
  // module id, usually the absolute path
  this.id = id;
  this.path = path.dirname(id);
  this.exports = {};
  // caller of the current module
  this.parent = parent;
  updateChildren(parent, this, false);
  this.filename = null;
  // whether the module has finished loading
  this.loaded = false;
  // modules required by this module
  this.children = [];
}

Modules can export via module.exports or by attaching properties to exports . The article shows examples of both approaches and explains the subtle differences when reassigning these variables.

// using exports
exports.name = 'xiaoxiang';
exports.add = (a, b) => a + b;
// using module.exports
module.exports = { add, minus };

Requiring a module can be done with a name, relative path, or absolute path, and the file extension (.js, .json, .node) may be omitted.

const { add, minus } = require('./module');
const a = require('/usr/app/module');
const http = require('http');

Module Loading Process

The core of the loading mechanism is the Module.prototype.require entry point, which delegates to Module._load . _load resolves the full filename, checks the cache, loads built‑in modules, or creates a new Module instance and caches it.

Module.prototype.require = function(id) {
  requireDepth++;
  try {
    return Module._load(id, this, false);
  } finally {
    requireDepth--;
  }
};

Module._load performs four steps: resolve the filename, handle three loading cases (cache hit, native module, file/third‑party module), cache the new module, load the file, and finally return module.exports .

Module._load = function(request, parent, isMain) {
  const filename = Module._resolveFilename(request, parent, isMain);
  const cachedModule = Module._cache[filename];
  if (cachedModule !== undefined) return cachedModule.exports;
  const mod = loadNativeModule(filename, request);
  if (mod && mod.canBeRequiredByUsers) return mod.exports;
  const module = new Module(filename, parent);
  Module._cache[filename] = module;
  module.load(filename);
  return module.exports;
};

The filename resolution is handled by Module._resolveFilename , which builds a search path list, resolves relative and absolute paths, and throws a MODULE_NOT_FOUND error if the module cannot be located.

Module._resolveFilename = function(request, parent, isMain, options) {
  if (NativeModule.canBeRequiredByUsers(request)) return request;
  // build search paths, handle relative/absolute, etc.
  const filename = Module._findPath(request, paths, isMain);
  if (!filename) throw new Error(`Cannot find module '${request}'`);
  return filename;
};

When the target is a directory, tryPackage reads package.json to obtain the main entry or falls back to index . The article also explains how _resolveLookupPaths and _findPath work together to locate the actual file.

File Extension Handling

Node registers handlers for .js , .json , and .node . The .js handler reads the file with fs.readFileSync and compiles it via module._compile . The .json handler parses the content with JSONParse . The .node handler loads native binaries using process.dlopen .

Module._extensions[".js"] = function(module, filename) {
  const content = fs.readFileSync(filename, "utf8");
  module._compile(content, filename);
};

Module._extensions[".json"] = function(module, filename) {
  const content = fs.readFileSync(filename, "utf8");
  module.exports = JSONParse(stripBOM(content));
};

Module._extensions[".node"] = function(module, filename) {
  return process.dlopen(module, path.toNamespacedPath(filename));
};

Compilation and Execution

For JavaScript files, module._compile wraps the source code, injects the module‑scoped variables ( exports , require , module , __filename , __dirname ), and executes the wrapped function in a V8 sandbox.

Module.prototype._compile = function(content, filename) {
  const compiledWrapper = wrapSafe(filename, content, this);
  const dirname = path.dirname(filename);
  const require = makeRequireFunction(this);
  const exports = this.exports;
  const module = this;
  const result = compiledWrapper.call(exports, exports, require, module, filename, dirname);
  this.loaded = true;
  return result;
};

The article concludes by emphasizing the elegance of Node’s module system and encourages readers to continue exploring its internals.

backendJavaScriptNode.jsModule SystemRequireCommonJS
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.