README
14.1 Module Systems Overview
π Introduction
Before ES6 modules, JavaScript had no built-in module system. Developers created various solutions to organize code into reusable, maintainable pieces. Understanding these systems helps you work with legacy code and appreciate why ES Modules became the standard.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EVOLUTION OF JAVASCRIPT MODULES β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1995-2009 2009-2015 2015-Present Future β
β βββββββββββ βββββββββββ βββββββββββββββ ββββββββββββ β
β β Global β βββΆ βCommonJS β βββΆ β ES Modules β βΆβΆ β Import β β
β β Scripts β β AMD β β (ESM) β β Maps β β
β β IIFE β β UMD β β β β β β
β βββββββββββ βββββββββββ βββββββββββββββ ββββββββββββ β
β β
β Problems: Solutions: Standard: Enhanced: β
β β’ Globals β’ Node.js β’ Native β’ Dynamic β
β β’ Collisions β’ Browsers β’ Static β’ Lazy load β
β β’ Dependencies β’ Bundlers β’ Tree-shake β’ Federated β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π― Learning Objectives
By the end of this section, you will:
- β’β Understand why modules are essential in JavaScript
- β’β Know the history and evolution of module systems
- β’β Compare different module formats (IIFE, CommonJS, AMD, UMD, ESM)
- β’β Recognize which system to use in different environments
- β’β Understand how bundlers bridge different module systems
1οΈβ£ The Problem: Why We Need Modules
Before Modules: The Global Nightmare
// file1.js
var userName = 'Alice';
var userAge = 25;
function greet() {
console.log('Hello, ' + userName);
}
// file2.js - OOPS! Overwrites file1's variables!
var userName = 'Bob'; // π₯ Collision!
var greet = 'Hi there'; // π₯ Function overwritten!
// file3.js - Which userName? Which greet?
greet(); // TypeError: greet is not a function
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β THE GLOBAL SCOPE PROBLEM β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β <script src="jquery.js"></script> ββ β
β <script src="lodash.js"></script> β β
β <script src="utils.js"></script> βββΆ ALL share ONE β
β <script src="app.js"></script> β global namespace! β
β <script src="analytics.js"></script> ββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β GLOBAL NAMESPACE (window) β β
β β ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬βββββββββββββββββ β β
β β β $ β _ β utils β app β gtag ... β β β
β β β(jQuery)β(lodash)β β β β β β
β β ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββββββββββ β β
β β β β
β β Problems: β β
β β β’ Name collisions (multiple libs use same names) β β
β β β’ Implicit dependencies (load order matters!) β β
β β β’ No encapsulation (everything is public) β β
β β β’ Hard to maintain and test β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
What Modules Solve
| Problem | Without Modules | With Modules |
|---|---|---|
| Namespace | Everything global | Private by default |
| Dependencies | Implicit (script order) | Explicit (import/export) |
| Reusability | Copy-paste code | Import and reuse |
| Encapsulation | All variables public | Choose what to expose |
| Maintainability | Spaghetti code | Clear structure |
| Testing | Hard to isolate | Easy to mock |
2οΈβ£ Early Solutions: IIFE Pattern
Immediately Invoked Function Expression
Before module systems, developers used IIFEs (Immediately Invoked Function Expressions) to create private scope:
// The IIFE Pattern - Creating Private Scope
var MyModule = (function () {
// Private variables - not accessible outside
var privateCounter = 0;
var privateData = 'secret';
// Private function
function privateLog(msg) {
console.log('[Private]:', msg);
}
// Return public API (Revealing Module Pattern)
return {
// Public method
increment: function () {
privateCounter++;
privateLog('Counter is now ' + privateCounter);
},
// Public method
getCount: function () {
return privateCounter;
},
// Public property
version: '1.0.0',
};
})();
// Usage
MyModule.increment(); // [Private]: Counter is now 1
console.log(MyModule.getCount()); // 1
console.log(MyModule.version); // "1.0.0"
console.log(MyModule.privateCounter); // undefined (private!)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β IIFE PATTERN β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β (function() { βββ Immediately invoked β
β β β
β β βββββββββββββββββββββββββββββββββββββββ β
β β β PRIVATE SCOPE β β
β β β βββββββββββββββββββββββββββββββ β β
β β β β var secret = "hidden"; β β β
β β β β function helper() {...} β β Not accessible β
β β β β var internalState = {}; β β from outside β
β β β βββββββββββββββββββββββββββββββ β β
β β βββββββββββββββββββββββββββββββββββββββ β
β β β
β β return { βββ Only these are exposed β
β β publicMethod: function() {...}, β
β β publicProperty: value β
β β }; β
β β β
β })(); β
β β
β βββββββββββββββββββββββββββββββββββββββ β
β β β Creates private scope β β
β β β Exposes only public API β β
β β β Still uses one global variable β β
β β β No dependency management β β
β β β Manual ordering of scripts β β
β βββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
IIFE with Dependencies
// Passing dependencies to IIFE
var MyApp = (function ($, _, config) {
// $ is jQuery, _ is Lodash, config is our config object
function init() {
$('.container').html(_.template('<h1><%= title %></h1>')(config));
}
return { init: init };
})(jQuery, lodash, AppConfig); // Pass dependencies
// Still requires correct script loading order!
// <script src="jquery.js"></script>
// <script src="lodash.js"></script>
// <script src="config.js"></script>
// <script src="myapp.js"></script> β Must be last!
3οΈβ£ CommonJS (CJS)
Created for Node.js (2009)
CommonJS was designed for server-side JavaScript (Node.js) where files are loaded from disk synchronously.
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// math.js - Exporting a module
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Private to this module
const PI = 3.14159;
const E = 2.71828;
// Public functions
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
function circleArea(radius) {
return PI * radius * radius;
}
// Export public API
module.exports = {
add,
multiply,
circleArea,
PI, // Can also export constants
};
// Alternative: Export individual items
// exports.add = add;
// exports.multiply = multiply;
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// app.js - Importing the module
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Import entire module
const math = require('./math');
console.log(math.add(2, 3)); // 5
console.log(math.circleArea(10)); // 314.159
console.log(math.PI); // 3.14159
// Destructuring import
const { add, multiply } = require('./math');
console.log(add(5, 5)); // 10
console.log(multiply(4, 3)); // 12
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β COMMONJS FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββ ββββββββββββββββ β
β β math.js β β app.js β β
β ββββββββββββββββ€ ββββββββββββββββ€ β
β β β β β β
β β const PI=3.14β β const math = β β
β β β βββββββ β require β β
β β function add β β ('./math') β β
β β function mul β β β β
β β β β math.add() β β
β β module. β βββββββΆ β math.PI β β
β β exports={ β β β β
β β add, mul, β β β β
β β PI β β β β
β β } β β β β
β ββββββββββββββββ ββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β HOW require() WORKS: β β
β β β β
β β 1. Resolve: Find the file path β β
β β 2. Load: Read file from disk (synchronous!) β β
β β 3. Wrap: Wrap in function with module, exports, require β β
β β 4. Execute: Run the wrapped code β β
β β 5. Cache: Store result for future require() calls β β
β β 6. Return: Return module.exports β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Characteristics: β
β β Synchronous loading (good for server, file system) β
β β Simple syntax β
β β Caching built-in β
β β Not suitable for browsers (synchronous = blocking) β
β β Dynamic - can't be statically analyzed β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CommonJS Dynamic Nature
// CommonJS allows dynamic requires (but not recommended)
const moduleName = someCondition ? 'moduleA' : 'moduleB';
const dynamicModule = require(`./${moduleName}`);
// Conditional requires
if (process.env.NODE_ENV === 'development') {
const debug = require('debug-module');
debug.enable();
}
// require() can be called anywhere
function loadPlugin(name) {
return require(`./plugins/${name}`);
}
4οΈβ£ AMD (Asynchronous Module Definition)
Designed for Browsers (2010)
AMD was created specifically for browsers where asynchronous loading is essential to prevent blocking the page.
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// math.js - Define an AMD module
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
define('math', [], function () {
// Module code
const PI = 3.14159;
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
// Return public API
return {
add: add,
multiply: multiply,
PI: PI,
};
});
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// app.js - Require AMD modules
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Require with dependencies
require(['jquery', 'math', 'utils'], function ($, math, utils) {
// All dependencies loaded asynchronously
// This callback runs when ALL are ready
$('.result').text(math.add(10, 20));
utils.log('Calculation complete!');
});
// Module with dependencies
define('calculator', ['math', 'logger'], function (math, logger) {
// math and logger are loaded first
function calculate(a, b, operation) {
logger.log(`Calculating ${a} ${operation} ${b}`);
switch (operation) {
case '+':
return math.add(a, b);
case '*':
return math.multiply(a, b);
default:
throw new Error('Unknown operation');
}
}
return { calculate };
});
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AMD LOADING β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β require(['A', 'B', 'C'], function(A, B, C) { ... }); β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β BROWSER β β
β β β β
β β βββββββ βββββββ βββββββ β β
β β β A β β B β β C β β Parallel Load β β
β β ββββ¬βββ ββββ¬βββ ββββ¬βββ β β
β β β β β β β
β β βΌ βΌ βΌ β β
β β βββββββββββββββββββββββββββββββ β β
β β β Wait for ALL to load β β β
β β βββββββββββββββ¬ββββββββββββββββ β β
β β β β β
β β βΌ β β
β β βββββββββββββββββββββββββββββββ β β
β β β Execute callback with β β β
β β β resolved dependencies β β β
β β βββββββββββββββββββββββββββββββ β β
β β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Characteristics: β
β β Asynchronous (non-blocking) β
β β Parallel loading β
β β Designed for browsers β
β β RequireJS is the main implementation β
β β Verbose syntax β
β β Wrapper function required β
β β Less popular now (ESM replaced it) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
5οΈβ£ UMD (Universal Module Definition)
Works Everywhere
UMD is a hybrid format that works in CommonJS (Node.js), AMD (RequireJS), and as a global variable (browser scripts).
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// UMD Pattern - Universal Module Definition
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD environment (RequireJS)
define(['dependency'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS environment (Node.js)
module.exports = factory(require('dependency'));
} else {
// Browser globals
root.MyLibrary = factory(root.Dependency);
}
})(typeof self !== 'undefined' ? self : this, function (dependency) {
// Module code here
function greet(name) {
return `Hello, ${name}!`;
}
function farewell(name) {
return `Goodbye, ${name}!`;
}
// Return public API
return {
greet: greet,
farewell: farewell,
version: '1.0.0',
};
});
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β UMD COMPATIBILITY β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ β
β β UMD WRAPPER β β
β β (Detects β β
β β Environment) β β
β ββββββββββ¬βββββββββ β
β β β
β ββββββββββββββββββΌβββββββββββββββββ β
β β β β β
β βΌ βΌ βΌ β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β AMD β β CommonJS β β Global β β
β β β β β β β β
β β define() β β require()β β window. β β
β β require()β β exports β β MyLib β β
β β β β β β β β
β β Browser β β Node.js β β Browser β β
β β RequireJSβ β β β <script> β β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β
β When to use UMD: β
β β Publishing a library that works everywhere β
β β Supporting legacy environments β
β β When consumers use different module systems β
β β
β Modern alternative: β
β β’ Build ESM + CJS + UMD versions with bundler β
β β’ Let package.json "exports" field handle resolution β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
6οΈβ£ ES Modules (ESM) - The Standard
Native JavaScript Modules (ES6/2015)
ES Modules are the official standard built into JavaScript itself.
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// math.js - ES Module exports
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Named exports
export const PI = 3.14159;
export const E = 2.71828;
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// Private (not exported)
function internalHelper() {
return "I'm private!";
}
// Default export (one per module)
export default class Calculator {
add(a, b) {
return a + b;
}
subtract(a, b) {
return a - b;
}
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// app.js - ES Module imports
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Import named exports
import { add, multiply, PI } from './math.js';
// Import default export
import Calculator from './math.js';
// Import all as namespace
import * as math from './math.js';
// Rename imports
import { add as sum, multiply as product } from './math.js';
// Import both default and named
import Calculator, { PI, E } from './math.js';
// Usage
console.log(add(2, 3)); // 5
console.log(PI); // 3.14159
const calc = new Calculator();
console.log(calc.add(10, 5)); // 15
console.log(math.multiply(4, 5)); // 20
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ES MODULES - THE STANDARD β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β KEY FEATURES β β
β β β β
β β β Static structure (analyzed at compile time) β β
β β β Tree-shaking (dead code elimination) β β
β β β Native browser support β β
β β β Async loading built-in β β
β β β Strict mode by default β β
β β β Top-level await (ES2022) β β
β β β Live bindings (exports are live references) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Static vs Dynamic: β
β β
β βββββββββββββββββββββββ βββββββββββββββββββββββ β
β β CommonJS β β ES Modules β β
β β (Dynamic) β β (Static) β β
β βββββββββββββββββββββββ€ βββββββββββββββββββββββ€ β
β β β β β β
β β // Works β β // ERROR! β β
β β if (cond) { β β if (cond) { β β
β β require('./a'); β β import './a'; β β
β β } β β } β β
β β β β β β
β β // Works β β // Use dynamic β β
β β require(variable); β β // import() instead β β
β β β β import(variable); β β
β β β β β β
β βββββββββββββββββββββββ βββββββββββββββββββββββ β
β β
β Static structure enables: β
β β’ Tree-shaking (remove unused exports) β
β β’ Static analysis (IDE support, type checking) β
β β’ Faster loading (parallel fetch) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
7οΈβ£ Module Systems Comparison
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MODULE SYSTEMS COMPARISON β
ββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬ββββββββββββββββββββββββββ€
β Feature β CommonJS β AMD β UMD β ES Modules β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Syntax β require() β define() β (complex) β import/export β
β β exports β require() β β β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Loading β Synchronous β Asynchronous β Depends β Asynchronous β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Analysis β Dynamic β Dynamic β Dynamic β Static β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Tree β β No β β No β β No β β
Yes β
β Shaking β β β β β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Browser β β Needs β β
Yes β β
Yes β β
Yes (native) β
β Support β bundler β (RequireJS) β β β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Node.js β β
Native β β No β β
Yes β β
Yes (.mjs or β
β Support β β β β "type":"module") β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Usage β Node.js, β Legacy β Universal β Modern JS β
β Today β Legacy β browser β libraries β Standard β
ββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Future β Declining β Deprecated β Still used β β
THE STANDARD β
β β β β for libs β β
ββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄ββββββββββββββββββββββββββ
8οΈβ£ When to Use Which
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CHOOSING A MODULE SYSTEM β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β NEW PROJECT? β β
β β β β
β β β USE ES MODULES β β
β β β’ Modern standard β β
β β β’ Best tooling support β β
β β β’ Tree-shaking β β
β β β’ Works in browsers and Node.js β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β LEGACY NODE.JS PROJECT? β β
β β β β
β β β COMMONJS is fine β β
β β β’ Existing codebase uses it β β
β β β’ Can migrate to ESM gradually β β
β β β’ Set "type": "module" in package.json to use ESM β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PUBLISHING A LIBRARY? β β
β β β β
β β β BUILD MULTIPLE FORMATS β β
β β β’ ESM for modern bundlers (tree-shaking) β β
β β β’ CJS for Node.js compatibility β β
β β β’ Use package.json "exports" field β β
β β β β
β β package.json: β β
β β { β β
β β "main": "./dist/index.cjs", β β
β β "module": "./dist/index.mjs", β β
β β "exports": { β β
β β "import": "./dist/index.mjs", β β
β β "require": "./dist/index.cjs" β β
β β } β β
β β } β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
9οΈβ£ Summary
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β KEY TAKEAWAYS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β π HISTORY: β
β Global scripts β IIFE β CommonJS/AMD β UMD β ES Modules β
β β
β π― ES MODULES ARE THE FUTURE: β
β β’ Native JavaScript standard β
β β’ Supported in all modern browsers and Node.js β
β β’ Enable tree-shaking and static analysis β
β β’ Use import/export syntax β
β β
β π§ COMMONJS STILL MATTERS: β
β β’ Used in older Node.js code β
β β’ Many npm packages still use it β
β β’ require()/module.exports syntax β
β β
β π¦ BUNDLERS BRIDGE THE GAP: β
β β’ Webpack, Rollup, Vite, esbuild β
β β’ Convert between module formats β
β β’ Enable ESM in older browsers β
β β
β π RECOMMENDATION: β
β β’ New projects: Use ES Modules β
β β’ Libraries: Build both ESM and CJS β
β β’ Legacy: Migrate gradually to ESM β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Next Steps
Continue to 14.2 ES Modules Syntax to learn:
- β’All import/export variations
- β’Dynamic imports
- β’Module aggregation
- β’Top-level await