JS: CommonJS (tutorial)

By Xah Lee. Date: . Last updated: .

explain the common.js module system

explain the common.js module system

(ai answer)

CommonJS is a specification for JavaScript modules that was originally developed to standardize module loading in server-side environments, particularly for Node.js. It provides a way to organize code into reusable, encapsulated units (modules) that can depend on and export functionality to other modules. Unlike browser-based JavaScript (which historically lacked native module support), CommonJS treats each file as a separate module, enabling better code organization, dependency management, and avoidance of global namespace pollution.

CommonJS is synchronous by design, meaning modules are loaded and executed immediately when required, which makes it well-suited for server-side applications where startup time is less critical than in browsers. It's the foundation of Node.js's module system (via the require function) and has influenced tools like Webpack and Browserify for bundling client-side code.

Core Concepts

  1. Modules as Files: Each JavaScript file (e.g., math.js) is treated as a self-contained module. There's no global scope shared between modules—each runs in its own isolated context.

  2. Exports: A module defines what it makes available to other modules via an exports object (or module.exports for the entire module).

  3. Imports: Other modules load dependencies using require(), which returns the exported value.

  4. Scope: Inside a module, this refers to the module.exports object. The exports variable is a shorthand reference to module.exports, but reassigning exports doesn't affect module.exports—always use module.exports for full exports.

How It Works: Basic Example

Let's say we have two files: math.js (a module to export) and app.js (the main file that uses it).

math.js (exporting functions):

// Define some functions
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

// Export an object with the functions
exports.add = add;
exports.subtract = subtract;

// Or, equivalently, for the entire module:
// module.exports = { add, subtract };

app.js (importing and using the module):

// Load the module synchronously
const math = require('./math.js');  // Path relative to app.js

// Use the exported functions
console.log(math.add(5, 3));     // Output: 8
console.log(math.subtract(5, 3)); // Output: 2

Exporting the Entire Module

You can export a single value (e.g., a class, function, or primitive) by assigning directly to module.exports:

// In greet.js
function greet(name) {
  return `Hello, ${name}!`;
}

module.exports = greet;  // Exports the function itself

Then import it:

const greet = require('./greet.js');
console.log(greet('World'));  // Output: Hello, World!

Common Patterns and Gotchas

Aspect CommonJS Example Notes
Named Export exports.foo = 42; Multiple per module
Full Export module.exports = { foo: 42 }; Replaces entire exports
Import const mod = require('./mod.js'); Synchronous, cached
Runtime Node.js, Browserify, Webpack Server-focused

Pros and Cons

Pros:

Cons:

Relation to ES Modules

CommonJS predates ECMAScript (ES) modules (introduced in ES6). ES modules use import/export syntax and are asynchronous/static, making them better for browsers and modern bundlers. Many tools (e.g., Babel) can transpile between them. If you're starting a new project, consider ES modules for future-proofing, but CommonJS remains dominant in legacy Node.js code.

For hands-on practice, try running the examples in a Node.js environment (node app.js). If you have specific aspects (e.g., integration with npm or errors), let me know!