JS: CommonJS Module System. 2009 to 2026
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
-
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. -
Exports: A module defines what it makes available to other modules via an
exportsobject (ormodule.exportsfor the entire module). -
Imports: Other modules load dependencies using
require(), which returns the exported value. -
Scope: Inside a module,
thisrefers to themodule.exportsobject. Theexportsvariable is a shorthand reference tomodule.exports, but reassigningexportsdoesn't affectmodule.exports—always usemodule.exportsfor 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
- When
require('./math.js')is called, Node.js (or a CommonJS runtime) executesmath.jsonce, caches the result, and returns theexportsobject. - Subsequent
requirecalls for the same module return the cached value (no re-execution).
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
- Default Exports: CommonJS doesn't have "default" exports like ES modules; everything is named or the whole module.
- Circular Dependencies: If two modules require each other, CommonJS handles it by providing partial exports during loading, but this can lead to bugs—avoid if possible.
- Node.js Extensions: In Node.js, you can use
.mjsfor ES modules alongside CommonJS, or set"type": "module"inpackage.jsonto switch. - Third-Party Modules: Most npm packages use CommonJS, so
require('lodash')works out of the box.
| 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:
- Simple and intuitive for backend code.
- Excellent caching prevents redundant execution.
- Wide adoption in the Node.js ecosystem.
Cons:
- Synchronous loading can block I/O in large apps (though rare in practice).
- Less flexible for tree-shaking (dead code elimination) compared to ES modules.
- Not native in browsers; requires bundlers for client-side use.
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!
History of CommonJS
history of CommonJS
ai answer
CommonJS emerged as a pivotal standardization effort in the JavaScript ecosystem, addressing the lack of a native module system in the language during the late 2000s.
At the time, JavaScript was primarily used in browsers via <script> tags, leading to global namespace pollution, dependency management issues, and brittle code organization through patterns like the Immediately Invoked Function Expression (IIFE) or the Module Pattern.
The rise of server-side JavaScript, particularly with early runtimes like SpiderMonkey and Narwhal, highlighted the need for a reusable, encapsulated module system outside the browser.
Origins and Early Development (2009)
The project traces its roots to January 29, 2009, when Mozilla engineer Kevin Dangoor published a blog post titled "What Server-Side JavaScript Needs?". In it, he proposed a standardized module system to enable modular, server-side JavaScript development, emphasizing synchronous loading for simplicity in non-browser environments. This initiative launched under the name ServerJS, focusing initially on server-side needs.
By August 2009, the project was renamed CommonJS to reflect its expanded scope beyond servers, encompassing any non-browser JavaScript runtime, such as desktop apps or embedded systems. The CommonJS group operated as an open, community-driven effort—not affiliated with Ecma International's TC39 (which handles ECMAScript standards)—where specifications were only finalized after multiple independent implementations proved viability. Early contributors included Dangoor and a loose collective of developers, with Isaac Z. Schlueter later playing a key role through Node.js integration.
The first major specification, Modules/1.0, defined the core mechanics: each file as a module, require() for synchronous imports, and exports (or module.exports) for sharing functionality.
This was quickly iterated to Modules/1.1 and 1.1.1, alongside supporting specs like Packages/1.0 for dependency management.
Adoption and Node.js Integration (2010–2011)
CommonJS gained traction with the launch of Node.js in May 2009 by Ryan Dahl.
By 2011, Node.js fully adopted CommonJS as its default module system, using require() and module.exports to enable reusable server-side code.
This made CommonJS the de facto standard for backend JavaScript, powering the explosive growth of npm (launched in 2010) where most packages were (and still are) published in CommonJS format.
Node's caching mechanism—executing modules once and reusing exports—optimized for server performance, though its synchronous nature suited I/O-bound environments better than browsers.
Expansion and Proposals (2010s)
The CommonJS project evolved beyond core modules, producing over 20 proposals for a broader API ecosystem. These included:
- Promises/B and Promises/D for asynchronous handling.
- HTTP Client/B and IO/A for network and file operations.
- Modules/Async/A and Modules/Transport series for experimental asynchronous loading (though sync remained dominant).
This "batteries-included" approach aimed for interoperability across JS runtimes, influencing tools like Narwhal and later Deno (in concept, though Deno favors ES modules).
Browser Challenges and Bundlers (2013–2015)
CommonJS wasn't natively browser-compatible, prompting workarounds. In 2013, Browserify emerged, allowing developers to write browser code in CommonJS syntax and bundle it into a single file for <script> inclusion. This bridged server and client, enabling npm modules in web apps but adding build-step complexity.
By 2015, Webpack (launched that year) built on this, creating dependency graphs for multi-asset bundling, further popularizing CommonJS in frontend workflows, especially with SPAs like React.
Transition to ES Modules and Legacy (2015–Present)
The landscape shifted with ECMAScript 2015 (ES6), which introduced native ES Modules using import/export syntax—static, asynchronous, and browser-native. This competed with CommonJS, offering better tree-shaking and no bundler requirement in modern browsers.
Node.js lagged in adoption: Experimental ES module support arrived in v8.5 (2018) and stabilized in v12 (2019), but CommonJS remains the default for backward compatibility. Today, interop is seamless—ES modules can import CommonJS via dynamic import()—and tools like TypeScript handle both.
| Milestone | Date | Key Event/Details |
|---|---|---|
| Proposal Launch | Jan 29, 2009 | Kevin Dangoor's blog post initiates ServerJS. |
| Rename | Aug 2009 | Becomes CommonJS for broader scope. |
| Node.js Adoption | 2011 | Default module system in Node.js. |
| Browserify | 2013 | Enables CommonJS in browsers via bundling. |
| ES6 Modules | 2015 | Native alternative introduced, shifting paradigms. |
| Node ES Support | 2019 | Experimental in v12; CommonJS persists. |
CommonJS's legacy endures: It democratized modular JS, birthing the npm ecosystem and influencing every modern bundler. While ES modules dominate new projects, CommonJS powers ~80% of legacy Node code and remains essential for migration paths. For deeper dives, explore the archived CommonJS wiki or Node's module docs.
JavaScript. Module Import Export
JavaScript history
- History of JavaScript, 1995 to 2025.
- The Ugly JavaScript. 2010 to 2026
- the History of JavaScript, by Brendan Eich. 2008
- HTML History Timeline. 1993 to 2011
- Netscape Browser Sucks (2002)
- JS: Version History. 1995 to 2025
- JavaScript history, prototype.js (2005 to 2010)
- JS: ECMAScript New Features. 2015 to 2026
- History of the HTML Script Tag (JavaScript) (2011)
- JavaScript History. Sharp Variable for Circular Reference (via Common Lisp Reader Macro Syntax)
- JavaScript the Good Parts, Douglas Crockford. 2008
- JavaScript The Definitive Guide by David Flanagan. 2011, 2020.
- History of Node.js by Ryan Dahl 2011 📺
- Apache vs Node.js vs NGINX 📺. (2013 humor)
- History of Angular.js (2018)
- CoffeeScript or JavaScript (2011)
- TypeScript Will Kill CoffeeScript and Dart (2012)
- Microsoft Apple Mozilla Dismiss Dart (2011)
- Stackoverflow dolts on JavaScript Compiler ES2015 to ES5. (Babel.js) (2014)
- JavaScript Brendan Eich on Fixing String Methods on Emoji (2019)
- JavaScript. Why not create a directive “use new js” to fix warts? (2019)
- JS: CommonJS Module System. 2009 to 2026
- JS: AMD Module System and history (2009 to 2016)
- npm Disease (2021)
modern web dev history. 2010 to 2026
- The Ugly JavaScript. 2010 to 2026
- Modern JavaScript Explained For Dinosaurs. By Peter Jang. 2017
- JS: ECMAScript 2015
- JS: CommonJS Module System. 2009 to 2026
- History of JavaScript, 1995 to 2025.
- npm Disease (2021)
- Why was Electron Created (JavaScript framework, 2013)
- JavaScript runtime platforms. 2009 to 2026
- JavaScript package managers. 2012 to 2026
- JavaScript bundlers. 2011 to 2026
- JavaScript UI Frameworks. 2010 to 2026
- JavaScript compilers. 2012 to 2026
- JavaScript task runners. 2012 to 2026
- JavaScript build tools (2026)