Docs

README

22.4 ES Modules Internals

Understanding how ES Modules work internally helps you write better module code, avoid circular dependency issues, and optimize load performance.


Table of Contents

  1. β€’Module System Overview
  2. β€’Module Loading Phases
  3. β€’Module Records and Environments
  4. β€’Circular Dependencies
  5. β€’Dynamic Imports
  6. β€’Module Caching
  7. β€’Top-Level Await
  8. β€’CommonJS vs ES Modules
  9. β€’All JavaScript Module Systems

Module System Overview

ES Modules are JavaScript's native module system, designed for static analysis and optimization.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    ES MODULES OVERVIEW                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  KEY CHARACTERISTICS:                                               β”‚
β”‚                                                                     β”‚
β”‚  1. STATIC STRUCTURE                                                β”‚
β”‚     β€’ Imports/exports determined at compile time                    β”‚
β”‚     β€’ Enables tree-shaking and dead code elimination               β”‚
β”‚     β€’ Cannot conditionally import (at top level)                   β”‚
β”‚                                                                     β”‚
β”‚  2. LIVE BINDINGS                                                   β”‚
β”‚     β€’ Imports are references, not copies                           β”‚
β”‚     β€’ Changes in exporter reflect in importer                      β”‚
β”‚                                                                     β”‚
β”‚  3. SINGLETON MODULES                                               β”‚
β”‚     β€’ Each module executed only once                                β”‚
β”‚     β€’ Cached for all subsequent imports                             β”‚
β”‚                                                                     β”‚
β”‚  4. STRICT MODE BY DEFAULT                                          β”‚
β”‚     β€’ All ES modules run in strict mode                            β”‚
β”‚     β€’ No need for 'use strict'                                     β”‚
β”‚                                                                     β”‚
β”‚  5. ASYNCHRONOUS LOADING                                            β”‚
β”‚     β€’ Modules can be loaded in parallel                             β”‚
β”‚     β€’ Execution happens after all dependencies ready               β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Static vs Dynamic

// βœ… STATIC - Analyzed at compile time
import { foo } from './module.js';
export const bar = 42;

// ❌ NOT STATIC - These are errors at top level
// if (condition) {
//   import { foo } from './module.js'; // Error!
// }

// βœ… DYNAMIC - Use dynamic import for runtime decisions
if (condition) {
  const { foo } = await import('./module.js'); // OK!
}

Module Loading Phases

ES Module loading happens in three distinct phases.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    MODULE LOADING PHASES                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  PHASE 1: CONSTRUCTION (Parsing)                                    β”‚
β”‚  ────────────────────────────────                                  β”‚
β”‚  β€’ Fetch module source code                                         β”‚
β”‚  β€’ Parse the source code                                            β”‚
β”‚  β€’ Find import/export statements                                    β”‚
β”‚  β€’ Create Module Record (metadata)                                  β”‚
β”‚  β€’ Build dependency graph                                           β”‚
β”‚                                                                     β”‚
β”‚      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”     fetch      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”     parse              β”‚
β”‚      β”‚   URL   β”‚ ───────────→ β”‚  Source  β”‚ ───────────→ Module     β”‚
β”‚      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               Record    β”‚
β”‚                                                                     β”‚
β”‚  PHASE 2: INSTANTIATION (Linking)                                   β”‚
β”‚  ───────────────────────────────                                   β”‚
β”‚  β€’ Allocate memory for all exports                                  β”‚
β”‚  β€’ Link imports to exports (live bindings)                         β”‚
β”‚  β€’ NO CODE EXECUTED YET                                            β”‚
β”‚                                                                     β”‚
β”‚      Module A ─────────── exports ──────────→ binding               β”‚
β”‚           ↑                                       β”‚                 β”‚
β”‚           └──────────── imports β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚                                                                     β”‚
β”‚  PHASE 3: EVALUATION (Execution)                                    β”‚
β”‚  ─────────────────────────────────                                 β”‚
β”‚  β€’ Execute module code (top-level)                                  β”‚
β”‚  β€’ Fill export bindings with values                                 β”‚
β”‚  β€’ Depth-first, post-order execution                               β”‚
β”‚                                                                     β”‚
β”‚      Dependency tree:      Execution order:                         β”‚
β”‚           A                     C (first)                           β”‚
β”‚          / \                    D (second)                          β”‚
β”‚         B   C                   B (third)                           β”‚
β”‚         |                       A (last)                            β”‚
β”‚         D                                                           β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Phase Details

// main.js
import { value, increment } from './counter.js';

console.log(value); // What happens here?
increment();
console.log(value); // And here?
// counter.js
export let value = 0;

export function increment() {
  value++;
}
PHASE 1: CONSTRUCTION
────────────────────
1. Parse main.js β†’ finds import from './counter.js'
2. Fetch and parse counter.js
3. Build Module Records for both

PHASE 2: INSTANTIATION
─────────────────────
1. Allocate memory for counter.js exports (value, increment)
2. Link main.js imports to counter.js exports
3. Both modules ready, no code run yet

PHASE 3: EVALUATION
──────────────────
1. Execute counter.js first (dependency)
   - value = 0
   - increment function created
2. Execute main.js
   - console.log(value) β†’ 0
   - increment() β†’ value becomes 1
   - console.log(value) β†’ 1 (live binding!)

Module Records and Environments

The JavaScript engine creates internal structures to manage modules.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    MODULE RECORD                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  [[Realm]]              The realm this module belongs to            β”‚
β”‚  [[Environment]]        Module's lexical environment                β”‚
β”‚  [[Namespace]]          Module namespace object                     β”‚
β”‚  [[Status]]             unlinked | linking | linked |              β”‚
β”‚                         evaluating | evaluated | error              β”‚
β”‚  [[RequestedModules]]   List of module specifiers                  β”‚
β”‚  [[ImportEntries]]      List of import entries                     β”‚
β”‚  [[LocalExportEntries]] List of local export entries               β”‚
β”‚  [[StarExportEntries]]  Re-exports with *                          β”‚
β”‚                                                                     β”‚
β”‚  Example for:                                                       β”‚
β”‚  ────────────                                                      β”‚
β”‚  // module.js                                                       β”‚
β”‚  import { x } from './dep.js';                                     β”‚
β”‚  export const y = x + 1;                                           β”‚
β”‚  export function double(n) { return n * 2; }                       β”‚
β”‚                                                                     β”‚
β”‚  ImportEntries: [{                                                 β”‚
β”‚    ModuleRequest: './dep.js',                                      β”‚
β”‚    ImportName: 'x',                                                β”‚
β”‚    LocalName: 'x'                                                  β”‚
β”‚  }]                                                                 β”‚
β”‚                                                                     β”‚
β”‚  LocalExportEntries: [                                             β”‚
β”‚    { LocalName: 'y', ExportName: 'y' },                           β”‚
β”‚    { LocalName: 'double', ExportName: 'double' }                   β”‚
β”‚  ]                                                                  β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Module Namespace Object

// module.js
export const a = 1;
export const b = 2;
export function c() {
  return 3;
}

// main.js
import * as mod from './module.js';

console.log(mod);
// Module Namespace Object:
// {
//   a: 1,
//   b: 2,
//   c: [Function: c],
//   [Symbol.toStringTag]: 'Module'
// }

console.log(Object.keys(mod)); // ['a', 'b', 'c']
console.log(Object.isFrozen(mod)); // true (in some environments)

Circular Dependencies

ES Modules handle circular dependencies, but understanding how is crucial.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    CIRCULAR DEPENDENCIES                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  The Problem:                                                       β”‚
β”‚                                                                     β”‚
β”‚      a.js ──imports──→ b.js                                        β”‚
β”‚        ↑                  β”‚                                         β”‚
β”‚        └────importsβ”€β”€β”€β”€β”€β”€β”€β”˜                                        β”‚
β”‚                                                                     β”‚
β”‚  How ES Modules handle it:                                          β”‚
β”‚                                                                     β”‚
β”‚  1. Start evaluating a.js                                          β”‚
β”‚  2. Hit import from b.js                                           β”‚
β”‚  3. Pause a.js, start evaluating b.js                              β”‚
β”‚  4. b.js tries to import from a.js                                 β”‚
β”‚  5. a.js already started β†’ use CURRENT state                       β”‚
β”‚     (even though a.js hasn't finished!)                            β”‚
β”‚  6. Finish b.js evaluation                                         β”‚
β”‚  7. Continue a.js evaluation                                       β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Circular Dependency Example

// a.js
import { b } from './b.js';
console.log('a.js: b =', b);

export let a = 'a after';
console.log('a.js: a =', a);
// b.js
import { a } from './a.js';
console.log('b.js: a =', a); // undefined! a.js not finished yet

export let b = 'b after';
console.log('b.js: b =', b);
Execution trace when running a.js:

1. Start a.js
2. Hit "import { b } from './b.js'"
3. Pause a.js (a is allocated but NOT initialized)
4. Start b.js
5. b.js: "import { a } from './a.js'" β†’ a.js already started
6. b.js: console.log('b.js: a =', a) β†’ "a" is UNDEFINED
7. b.js: export b = 'b after'
8. b.js: console.log('b.js: b =', b) β†’ "b after"
9. b.js DONE
10. Resume a.js
11. a.js: console.log('a.js: b =', b) β†’ "b after"
12. a.js: export a = 'a after'
13. a.js: console.log('a.js: a =', a) β†’ "a after"

Output:
b.js: a = undefined
b.js: b = b after
a.js: b = b after
a.js: a = a after

Avoiding Circular Dependency Issues

// ❌ BAD: Accessing export before initialization
// a.js
import { b, getB } from './b.js';
export const a = b + 1; // b might be undefined!

// βœ… GOOD: Use functions that are called later
// a.js
import { getB } from './b.js';
export const a = 'a';
export function getA() {
  return a;
}
export function init() {
  console.log('b is:', getB()); // Called after both modules loaded
}

// b.js
import { getA } from './a.js';
export const b = 'b';
export function getB() {
  return b;
}
export function init() {
  console.log('a is:', getA());
}

Dynamic Imports

Dynamic imports allow loading modules at runtime.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    DYNAMIC IMPORTS                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  SYNTAX:                                                            β”‚
β”‚                                                                     β”‚
β”‚  const module = await import('./module.js');                       β”‚
β”‚                        β”‚                                            β”‚
β”‚                        └── Returns Promise<ModuleNamespace>         β”‚
β”‚                                                                     β”‚
β”‚  USE CASES:                                                         β”‚
β”‚                                                                     β”‚
β”‚  1. Code Splitting                                                  β”‚
β”‚     const { heavyFunction } = await import('./heavy.js');          β”‚
β”‚                                                                     β”‚
β”‚  2. Conditional Loading                                             β”‚
β”‚     if (needsFeature) {                                            β”‚
β”‚       const { feature } = await import('./feature.js');            β”‚
β”‚     }                                                               β”‚
β”‚                                                                     β”‚
β”‚  3. Computed Module Paths                                           β”‚
β”‚     const lang = 'en';                                              β”‚
β”‚     const i18n = await import(`./locales/${lang}.js`);             β”‚
β”‚                                                                     β”‚
β”‚  4. Lazy Loading                                                    β”‚
β”‚     button.onclick = async () => {                                 β”‚
β”‚       const { handleClick } = await import('./handler.js');        β”‚
β”‚       handleClick();                                                β”‚
β”‚     };                                                              β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Dynamic Import Patterns

// Pattern 1: Lazy Loading Components
async function loadComponent(name) {
  const components = {
    header: () => import('./components/header.js'),
    footer: () => import('./components/footer.js'),
    sidebar: () => import('./components/sidebar.js'),
  };

  return await components[name]?.();
}

// Pattern 2: Feature Detection
async function loadPolyfill() {
  if (!('IntersectionObserver' in window)) {
    await import('./polyfills/intersection-observer.js');
  }
}

// Pattern 3: Parallel Loading
async function loadAllFeatures() {
  const [featureA, featureB, featureC] = await Promise.all([
    import('./features/a.js'),
    import('./features/b.js'),
    import('./features/c.js'),
  ]);

  return { featureA, featureB, featureC };
}

// Pattern 4: Fallback Loading
async function loadWithFallback() {
  try {
    return await import('./feature-modern.js');
  } catch {
    return await import('./feature-legacy.js');
  }
}

Module Caching

Modules are cached after first loadβ€”understanding this is important.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    MODULE CACHE                                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  Module Map (Browser/Runtime maintains this):                       β”‚
β”‚                                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  URL / Specifier         β”‚  Module Record                  β”‚    β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€    β”‚
β”‚  β”‚  './counter.js'          β”‚  { exports: { count, inc } }   β”‚    β”‚
β”‚  β”‚  './utils.js'            β”‚  { exports: { helper } }       β”‚    β”‚
β”‚  β”‚  'lodash'                β”‚  { exports: { ... } }          β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                     β”‚
β”‚  First import('./counter.js'):                                      β”‚
β”‚  1. Check cache β†’ Not found                                        β”‚
β”‚  2. Fetch, parse, instantiate, evaluate                            β”‚
β”‚  3. Store in cache                                                  β”‚
β”‚                                                                     β”‚
β”‚  Second import('./counter.js'):                                     β”‚
β”‚  1. Check cache β†’ FOUND                                            β”‚
β”‚  2. Return cached module namespace                                  β”‚
β”‚  3. NO re-execution                                                 β”‚
β”‚                                                                     β”‚
β”‚  Implications:                                                      β”‚
β”‚  β€’ Module code runs ONCE                                           β”‚
β”‚  β€’ Module state is SHARED                                          β”‚
β”‚  β€’ Same object/function references across all imports              β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Singleton Pattern via Modules

// counter.js - This is a singleton!
let count = 0;

export function getCount() {
  return count;
}

export function increment() {
  count++;
}

// fileA.js
import { getCount, increment } from './counter.js';
increment();
console.log(getCount()); // 1

// fileB.js
import { getCount, increment } from './counter.js';
// Same module instance as fileA.js!
console.log(getCount()); // 1 (not 0!)
increment();
console.log(getCount()); // 2

Cache Busting (for Testing/Development)

// Adding a query string creates a "new" module
const counter1 = await import('./counter.js?v=1');
const counter2 = await import('./counter.js?v=2');

// counter1 and counter2 are DIFFERENT instances!
// Note: This is a workaround, not standard behavior

Top-Level Await

ES2022 allows await at the module's top level.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    TOP-LEVEL AWAIT                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  Before (ES2015):                                                   β”‚
β”‚  ────────────────                                                  β”‚
β”‚  // config.js                                                       β”‚
β”‚  export let config;                                                 β”‚
β”‚                                                                     β”‚
β”‚  (async () => {                                                    β”‚
β”‚    config = await loadConfig();                                     β”‚
β”‚  })();                                                              β”‚
β”‚                                                                     β”‚
β”‚  // Problem: config might be undefined when imported!              β”‚
β”‚                                                                     β”‚
β”‚  With Top-Level Await (ES2022):                                     β”‚
β”‚  ─────────────────────────────                                     β”‚
β”‚  // config.js                                                       β”‚
β”‚  export const config = await loadConfig();                         β”‚
β”‚                                                                     β”‚
β”‚  // Guaranteed: config is ready when module finishes loading       β”‚
β”‚                                                                     β”‚
β”‚  Execution Order with TLA:                                          β”‚
β”‚                                                                     β”‚
β”‚      main.js                                                        β”‚
β”‚         β”‚                                                           β”‚
β”‚    import                                                           β”‚
β”‚         β”‚                                                           β”‚
β”‚         β–Ό                                                           β”‚
β”‚      config.js ──── await loadConfig() ────                        β”‚
β”‚         β”‚                               β”‚                           β”‚
β”‚         β”‚                               β”‚ (async operation)        β”‚
β”‚         β”‚                               β”‚                           β”‚
β”‚         β–Ό β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                          β”‚
β”‚      continue main.js                                               β”‚
β”‚                                                                     β”‚
β”‚  The importing module WAITS for the async module to complete!      β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Top-Level Await Examples

// database.js
// Module evaluation waits for connection
const connection = await connectToDatabase();

export { connection };

export async function query(sql) {
  return connection.query(sql);
}

// app.js
import { connection, query } from './database.js';

// Connection is guaranteed to be established here
console.log('Connected:', connection.isConnected);
const users = await query('SELECT * FROM users');

TLA Considerations

// ⚠️ TLA can block loading of dependent modules
// config.js
export const config = await fetch('/api/config').then((r) => r.json());
// ↑ This blocks ALL modules that import config.js

// βœ… Better: Use TLA sparingly
// Consider if async initialization is really needed at import time
// Sometimes lazy initialization is better

// Alternative: Lazy initialization
let _config = null;

export async function getConfig() {
  if (!_config) {
    _config = await fetch('/api/config').then((r) => r.json());
  }
  return _config;
}

CommonJS vs ES Modules

Understanding the differences helps when working with both systems.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    CJS vs ESM COMPARISON                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚                     CommonJS              ES Modules                β”‚
β”‚  ─────────────────────────────────────────────────────────────────  β”‚
β”‚  Syntax           require()              import/export              β”‚
β”‚                   module.exports         export default/named       β”‚
β”‚                                                                     β”‚
β”‚  Loading          Synchronous            Asynchronous              β”‚
β”‚                   (blocking)             (non-blocking)             β”‚
β”‚                                                                     β”‚
β”‚  Resolution       Runtime                Static (compile time)     β”‚
β”‚                   Dynamic                Known before execution     β”‚
β”‚                                                                     β”‚
β”‚  Bindings         Value copy             Live bindings             β”‚
β”‚                   (snapshot)             (reference)               β”‚
β”‚                                                                     β”‚
β”‚  Evaluation       Immediate              Deferred                   β”‚
β”‚                   when required          after all parsing          β”‚
β”‚                                                                     β”‚
β”‚  Top-level        Sync only              Sync + Async (TLA)        β”‚
β”‚                                                                     β”‚
β”‚  this value       module object          undefined                  β”‚
β”‚                                                                     β”‚
β”‚  Tree-shaking     Not possible           Possible                   β”‚
β”‚                   (dynamic)              (static analysis)          β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Live Bindings vs Value Copy

// === CommonJS (Value Copy) ===

// counter.cjs
let count = 0;
module.exports = {
  count, // Copies current value
  increment: () => count++,
};

// main.cjs
const counter = require('./counter.cjs');
console.log(counter.count); // 0
counter.increment();
console.log(counter.count); // Still 0! (value was copied)

// === ES Modules (Live Binding) ===

// counter.mjs
export let count = 0;
export function increment() {
  count++;
}

// main.mjs
import { count, increment } from './counter.mjs';
console.log(count); // 0
increment();
console.log(count); // 1 (live binding - sees updated value)

Interoperability

// ESM importing CJS (usually works)
import lodash from 'lodash';  // CJS module
import { map } from 'lodash'; // May not work for named exports

// CJS importing ESM (requires dynamic import)
// const esm = require('./esm-module.mjs'); // ❌ Error!
const esm = await import('./esm-module.mjs'); // βœ… Works

// Package.json configuration
{
  "type": "module",     // Treat .js as ESM
  "exports": {
    "import": "./esm/index.js",
    "require": "./cjs/index.cjs"
  }
}

All JavaScript Module Systems

A comprehensive overview of all module systems in JavaScript history.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 JAVASCRIPT MODULE SYSTEMS TIMELINE                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  1999  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚        β”‚  IIFE Module Pattern (Pre-modules)                  β”‚      β”‚
β”‚        β”‚  First attempt at encapsulation                     β”‚      β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                                     β”‚
β”‚  2009  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚        β”‚  CommonJS (CJS)                                     β”‚      β”‚
β”‚        β”‚  Node.js server-side modules                        β”‚      β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                                     β”‚
β”‚  2011  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚        β”‚  AMD (Asynchronous Module Definition)               β”‚      β”‚
β”‚        β”‚  Browser async loading (RequireJS)                  β”‚      β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                                     β”‚
β”‚  2012  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚        β”‚  UMD (Universal Module Definition)                  β”‚      β”‚
β”‚        β”‚  Works everywhere (CJS + AMD + Global)              β”‚      β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                                     β”‚
β”‚  2015  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚        β”‚  ES6 Modules (ESM)                                  β”‚      β”‚
β”‚        β”‚  Native JavaScript modules                          β”‚      β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                                     β”‚
β”‚  2016+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚        β”‚  Bundler Modules (Webpack/Rollup/Vite)              β”‚      β”‚
β”‚        β”‚  Build-time module resolution                       β”‚      β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

1. IIFE Module Pattern (Old Module Pattern)

The original way to create private scope in JavaScript.

// IIFE (Immediately Invoked Function Expression) Module Pattern
const MyModule = (function () {
  // Private variables
  let privateVar = 0;
  const privateConst = 'secret';

  // Private function
  function privateFunction() {
    return privateVar * 2;
  }

  // Public API (Revealing Module Pattern)
  return {
    increment: function () {
      privateVar++;
    },
    getCount: function () {
      return privateVar;
    },
    getDouble: function () {
      return privateFunction();
    },
  };
})();

// Usage
MyModule.increment();
console.log(MyModule.getCount()); // 1
console.log(MyModule.privateVar); // undefined (private!)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    IIFE MODULE PATTERN                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  PROS:                                                              β”‚
β”‚  βœ… No dependencies or build tools needed                          β”‚
β”‚  βœ… Works in all browsers                                          β”‚
β”‚  βœ… Creates true private scope                                     β”‚
β”‚  βœ… Immediately executable                                         β”‚
β”‚                                                                     β”‚
β”‚  CONS:                                                              β”‚
β”‚  ❌ No dependency management                                       β”‚
β”‚  ❌ Relies on script order in HTML                                 β”‚
β”‚  ❌ No async loading                                               β”‚
β”‚  ❌ Global namespace pollution (module name)                       β”‚
β”‚  ❌ Outdated for modern development                                β”‚
β”‚                                                                     β”‚
β”‚  USE CASE: Legacy code, quick scripts, learning closures           β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. CommonJS (CJS)

The module system created for Node.js.

// math.js (CommonJS module)
const PI = 3.14159;

function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

// Export multiple items
module.exports = {
  PI,
  add,
  multiply,
};

// Or export individually
// exports.add = add;
// exports.PI = PI;
// main.js (CommonJS consumer)
const math = require('./math');
console.log(math.add(2, 3)); // 5
console.log(math.PI); // 3.14159

// Destructuring import
const { add, multiply } = require('./math');
console.log(multiply(4, 5)); // 20

// Conditional/dynamic require
if (needsMath) {
  const dynamicMath = require('./math');
}
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         COMMONJS                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  SYNTAX:                                                            β”‚
β”‚    require('./module')         // Import                            β”‚
β”‚    module.exports = { ... }    // Export object                     β”‚
β”‚    exports.name = value        // Export individual                 β”‚
β”‚                                                                     β”‚
β”‚  CHARACTERISTICS:                                                   β”‚
β”‚    β€’ Synchronous loading (blocking)                                 β”‚
β”‚    β€’ Runtime module resolution                                      β”‚
β”‚    β€’ Exports are value COPIES (not live bindings)                   β”‚
β”‚    β€’ Dynamic imports allowed anywhere                               β”‚
β”‚    β€’ Circular dependencies: partial exports                         β”‚
β”‚                                                                     β”‚
β”‚  PROS:                                                              β”‚
β”‚  βœ… Simple syntax                                                   β”‚
β”‚  βœ… Huge NPM ecosystem                                              β”‚
β”‚  βœ… Dynamic requires possible                                       β”‚
β”‚  βœ… Well-understood in Node.js                                      β”‚
β”‚                                                                     β”‚
β”‚  CONS:                                                              β”‚
β”‚  ❌ Synchronous (bad for browsers)                                  β”‚
β”‚  ❌ No static analysis (no tree-shaking)                            β”‚
β”‚  ❌ Not native to browsers                                          β”‚
β”‚  ❌ Being phased out for ESM in Node.js                            β”‚
β”‚                                                                     β”‚
β”‚  FILE EXTENSIONS: .js (with type: "commonjs") or .cjs              β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3. AMD (Asynchronous Module Definition)

Created for browsers to load modules asynchronously.

// math.js (AMD module)
define('math', [], function () {
  const PI = 3.14159;

  function add(a, b) {
    return a + b;
  }

  function multiply(a, b) {
    return a * b;
  }

  // Return public API
  return {
    PI: PI,
    add: add,
    multiply: multiply,
  };
});
// main.js (AMD consumer)
define(['math', 'utils'], function (math, utils) {
  // Dependencies are injected as arguments
  console.log(math.add(2, 3));
  console.log(utils.format('Hello'));
});

// Or using require
require(['math'], function (math) {
  console.log(math.PI);
});
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           AMD                                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  SYNTAX:                                                            β”‚
β”‚    define(id?, deps?, factory)    // Define module                  β”‚
β”‚    require(deps, callback)        // Load modules                   β”‚
β”‚                                                                     β”‚
β”‚  IMPLEMENTATIONS:                                                   β”‚
β”‚    β€’ RequireJS (most popular)                                       β”‚
β”‚    β€’ curl.js                                                        β”‚
β”‚    β€’ Dojo Toolkit                                                   β”‚
β”‚                                                                     β”‚
β”‚  CHARACTERISTICS:                                                   β”‚
β”‚    β€’ Asynchronous loading                                           β”‚
β”‚    β€’ Browser-first design                                           β”‚
β”‚    β€’ Callback-based API                                             β”‚
β”‚    β€’ Explicit dependency declaration                                β”‚
β”‚                                                                     β”‚
β”‚  PROS:                                                              β”‚
β”‚  βœ… Async loading (non-blocking)                                    β”‚
β”‚  βœ… Works in browsers without build step                           β”‚
β”‚  βœ… Parallel loading of dependencies                                β”‚
β”‚  βœ… Good for large applications                                     β”‚
β”‚                                                                     β”‚
β”‚  CONS:                                                              β”‚
β”‚  ❌ Verbose syntax                                                  β”‚
β”‚  ❌ Requires RequireJS library                                      β”‚
β”‚  ❌ Mostly obsolete (replaced by ESM + bundlers)                   β”‚
β”‚  ❌ Complex configuration                                           β”‚
β”‚                                                                     β”‚
β”‚  STATUS: Largely obsolete, replaced by ES Modules                   β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

4. UMD (Universal Module Definition)

Works in CommonJS, AMD, and browser globals.

// math.js (UMD module)
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['exports'], factory);
  } else if (
    typeof exports === 'object' &&
    typeof exports.nodeName !== 'string'
  ) {
    // CommonJS
    factory(exports);
  } else {
    // Browser globals
    factory((root.math = {}));
  }
})(typeof self !== 'undefined' ? self : this, function (exports) {
  // Module code here
  exports.PI = 3.14159;

  exports.add = function (a, b) {
    return a + b;
  };

  exports.multiply = function (a, b) {
    return a * b;
  };
});
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                            UMD                                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  PURPOSE: Universal compatibility wrapper                           β”‚
β”‚                                                                     β”‚
β”‚  WORKS IN:                                                          β”‚
β”‚    βœ“ Node.js (CommonJS)                                            β”‚
β”‚    βœ“ RequireJS (AMD)                                               β”‚
β”‚    βœ“ Browser script tags (global)                                  β”‚
β”‚                                                                     β”‚
β”‚  DETECTION ORDER:                                                   β”‚
β”‚    1. Check for AMD (define.amd)                                   β”‚
β”‚    2. Check for CommonJS (exports object)                          β”‚
β”‚    3. Fall back to browser global                                  β”‚
β”‚                                                                     β”‚
β”‚  PROS:                                                              β”‚
β”‚  βœ… Maximum compatibility                                           β”‚
β”‚  βœ… Single file works everywhere                                   β”‚
β”‚  βœ… Good for libraries                                              β”‚
β”‚                                                                     β”‚
β”‚  CONS:                                                              β”‚
β”‚  ❌ Very verbose boilerplate                                        β”‚
β”‚  ❌ Complex to write manually                                       β”‚
β”‚  ❌ Mostly generated by bundlers now                                β”‚
β”‚  ❌ Being replaced by ESM + CJS dual packages                      β”‚
β”‚                                                                     β”‚
β”‚  STATUS: Still used for library distribution, but declining         β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

5. ES6 Modules (ESM) - The Standard

Native JavaScript modules (covered in detail above).

// math.mjs (ES Module)
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

// Default export
export default class Calculator {
  add(a, b) {
    return a + b;
  }
}
// main.mjs (ES Module consumer)
import Calculator, { PI, add, multiply } from './math.mjs';
import * as math from './math.mjs';

console.log(add(2, 3)); // Named import
console.log(math.PI); // Namespace import
const calc = new Calculator(); // Default import

// Dynamic import
const module = await import('./math.mjs');
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    ES6 MODULES (ESM)                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  SYNTAX:                                                            β”‚
β”‚    import { x } from './mod.js'   // Named import                  β”‚
β”‚    import x from './mod.js'       // Default import                β”‚
β”‚    import * as mod from './mod'   // Namespace import              β”‚
β”‚    export const x = 1             // Named export                  β”‚
β”‚    export default x               // Default export                β”‚
β”‚    export { x, y }                // Export list                   β”‚
β”‚                                                                     β”‚
β”‚  THE STANDARD:                                                      β”‚
β”‚    β€’ Part of ECMAScript specification                               β”‚
β”‚    β€’ Native browser support                                         β”‚
β”‚    β€’ Native Node.js support (v12+)                                 β”‚
β”‚    β€’ Static structure enables optimization                         β”‚
β”‚                                                                     β”‚
β”‚  KEY FEATURES:                                                      β”‚
β”‚    βœ“ Static analysis / tree-shaking                                β”‚
β”‚    βœ“ Live bindings (not copies)                                    β”‚
β”‚    βœ“ Async loading                                                 β”‚
β”‚    βœ“ Top-level await                                               β”‚
β”‚    βœ“ Strict mode by default                                        β”‚
β”‚                                                                     β”‚
β”‚  FILE EXTENSIONS: .mjs or .js with "type": "module"                β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

6. NPM Package Module System

How npm packages expose modules.

// package.json
{
  "name": "my-library",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    },
    "./utils": {
      "import": "./dist/utils.mjs",
      "require": "./dist/utils.cjs"
    }
  },
  "files": ["dist"]
}
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    NPM PACKAGE EXPORTS                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  PACKAGE.JSON FIELDS:                                               β”‚
β”‚                                                                     β”‚
β”‚  "type": "module"        β†’ Treat .js as ESM                        β”‚
β”‚  "type": "commonjs"      β†’ Treat .js as CJS (default)              β”‚
β”‚                                                                     β”‚
β”‚  "main"                  β†’ CJS entry point (legacy)                β”‚
β”‚  "module"                β†’ ESM entry point (bundlers)              β”‚
β”‚  "browser"               β†’ Browser-specific entry                  β”‚
β”‚  "exports"               β†’ Modern entry points (recommended)       β”‚
β”‚                                                                     β”‚
β”‚  EXPORTS FIELD (Modern):                                            β”‚
β”‚  ────────────────────────                                          β”‚
β”‚  "exports": {                                                       β”‚
β”‚    ".": {                 // Main entry                            β”‚
β”‚      "import": "...",     // ESM import                            β”‚
β”‚      "require": "...",    // CJS require                           β”‚
β”‚      "types": "...",      // TypeScript                            β”‚
β”‚      "default": "..."     // Fallback                              β”‚
β”‚    },                                                               β”‚
β”‚    "./subpath": {...}     // Subpath exports                       β”‚
β”‚  }                                                                  β”‚
β”‚                                                                     β”‚
β”‚  DUAL PACKAGE PATTERN:                                              β”‚
β”‚  Publish both ESM and CJS for maximum compatibility                β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

7. Bundler-Based Modules

Modern bundlers transform and optimize modules.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    BUNDLER-BASED MODULES                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  BUNDLERS:                                                          β”‚
β”‚                                                                     β”‚
β”‚  WEBPACK                                                            β”‚
β”‚  β”œβ”€ Most configurable                                               β”‚
β”‚  β”œβ”€ Code splitting, lazy loading                                    β”‚
β”‚  β”œβ”€ Loaders for any file type                                      β”‚
β”‚  └─ Large plugin ecosystem                                          β”‚
β”‚                                                                     β”‚
β”‚  ROLLUP                                                             β”‚
β”‚  β”œβ”€ Best tree-shaking                                               β”‚
β”‚  β”œβ”€ Optimized for libraries                                         β”‚
β”‚  β”œβ”€ ESM-first design                                                β”‚
β”‚  └─ Smaller output bundles                                          β”‚
β”‚                                                                     β”‚
β”‚  VITE                                                               β”‚
β”‚  β”œβ”€ Uses native ESM in development                                  β”‚
β”‚  β”œβ”€ Extremely fast HMR                                              β”‚
β”‚  β”œβ”€ Rollup for production builds                                   β”‚
β”‚  └─ Zero-config for most projects                                  β”‚
β”‚                                                                     β”‚
β”‚  PARCEL                                                             β”‚
β”‚  β”œβ”€ Zero configuration                                              β”‚
β”‚  β”œβ”€ Built-in transforms                                             β”‚
β”‚  └─ Good for quick prototypes                                       β”‚
β”‚                                                                     β”‚
β”‚  esbuild                                                            β”‚
β”‚  β”œβ”€ Extremely fast (Go-based)                                       β”‚
β”‚  β”œβ”€ Basic but efficient                                             β”‚
β”‚  └─ Often used by other tools                                       β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
// Webpack example - webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [{ test: /\.js$/, use: 'babel-loader' }],
  },
  optimization: {
    splitChunks: { chunks: 'all' },
  },
};
// Vite example - vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    rollupOptions: {
      input: 'src/main.js',
      output: {
        manualChunks: {
          vendor: ['lodash', 'axios'],
        },
      },
    },
  },
});

8. Babel-Transpiled Modules

Babel transforms modern module syntax for older environments.

// Input: ES Modules
import { add } from './math.js';
export const result = add(1, 2);

// Output: CommonJS (after Babel)
('use strict');
Object.defineProperty(exports, '__esModule', { value: true });
exports.result = void 0;
var _math = require('./math.js');
var result = (0, _math.add)(1, 2);
exports.result = result;
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    BABEL MODULE TRANSFORMS                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  COMMON TRANSFORMS:                                                 β”‚
β”‚                                                                     β”‚
β”‚  @babel/plugin-transform-modules-commonjs                          β”‚
β”‚    β†’ ESM to CJS                                                     β”‚
β”‚                                                                     β”‚
β”‚  @babel/plugin-transform-modules-amd                               β”‚
β”‚    β†’ ESM to AMD                                                     β”‚
β”‚                                                                     β”‚
β”‚  @babel/plugin-transform-modules-umd                               β”‚
β”‚    β†’ ESM to UMD                                                     β”‚
β”‚                                                                     β”‚
β”‚  @babel/plugin-transform-modules-systemjs                          β”‚
β”‚    β†’ ESM to SystemJS                                                β”‚
β”‚                                                                     β”‚
β”‚  INTEROP HELPERS:                                                   β”‚
β”‚    __esModule marker                                                β”‚
β”‚    _interopRequireDefault                                           β”‚
β”‚    _interopRequireWildcard                                          β”‚
β”‚                                                                     β”‚
β”‚  PURPOSE:                                                           β”‚
β”‚  Write modern ESM β†’ Babel transforms to target format              β”‚
β”‚  Ensures compatibility with older Node.js/browsers                  β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

9. Top-Level Await (ESM Feature)

Covered in detail above. Key points:

// config.js (ESM with Top-Level Await)
const response = await fetch('/api/config');
export const config = await response.json();

// database.js
export const db = await connectToDatabase();

// main.js
import { config } from './config.js'; // Waits for config to load
import { db } from './database.js'; // Waits for connection

// Both are guaranteed ready here
console.log(config.apiUrl);
await db.query('SELECT * FROM users');

Module Systems Comparison

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    MODULE SYSTEMS COMPARISON                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Feature    β”‚  IIFE   β”‚   CJS   β”‚   AMD   β”‚   UMD   β”‚   ESM   β”‚  Bundler   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Async Load   β”‚   ❌    β”‚   ❌    β”‚   βœ…    β”‚   ❌    β”‚   βœ…    β”‚    βœ…      β”‚
β”‚ Tree-shake   β”‚   ❌    β”‚   ❌    β”‚   ❌    β”‚   ❌    β”‚   βœ…    β”‚    βœ…      β”‚
β”‚ Live Binding β”‚   ❌    β”‚   ❌    β”‚   ❌    β”‚   ❌    β”‚   βœ…    β”‚    βœ…      β”‚
β”‚ Static       β”‚   ❌    β”‚   ❌    β”‚   βœ…    β”‚   ❌    β”‚   βœ…    β”‚    βœ…      β”‚
β”‚ Browser      β”‚   βœ…    β”‚   ❌    β”‚   βœ…    β”‚   βœ…    β”‚   βœ…    β”‚    βœ…      β”‚
β”‚ Node.js      β”‚   βœ…    β”‚   βœ…    β”‚   ❌    β”‚   βœ…    β”‚   βœ…    β”‚    βœ…      β”‚
β”‚ Dynamic      β”‚   βœ…    β”‚   βœ…    β”‚   βœ…    β”‚   βœ…    β”‚   βœ…*   β”‚    βœ…      β”‚
β”‚ No Build     β”‚   βœ…    β”‚   βœ…    β”‚   βœ…    β”‚   βœ…    β”‚   βœ…    β”‚    ❌      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Status     β”‚ Legacy  β”‚ Legacy  β”‚ Obsoleteβ”‚ Fading  β”‚ Standardβ”‚   Modern   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

* ESM dynamic import via import()

Which Module System to Use?

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    DECISION GUIDE                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  NEW PROJECT (2024+):                                               β”‚
β”‚  ────────────────────                                              β”‚
β”‚  β†’ Use ES Modules (ESM) everywhere                                  β”‚
β”‚  β†’ Use a modern bundler (Vite, esbuild)                            β”‚
β”‚  β†’ Set "type": "module" in package.json                            β”‚
β”‚                                                                     β”‚
β”‚  LIBRARY/PACKAGE:                                                   β”‚
β”‚  ────────────────                                                  β”‚
β”‚  β†’ Publish dual CJS + ESM (exports field)                          β”‚
β”‚  β†’ Use Rollup or unbuild for bundling                              β”‚
β”‚  β†’ Include TypeScript types                                         β”‚
β”‚                                                                     β”‚
β”‚  LEGACY PROJECT:                                                    β”‚
β”‚  ───────────────                                                   β”‚
β”‚  β†’ Keep existing CommonJS if stable                                β”‚
β”‚  β†’ Migrate gradually to ESM                                         β”‚
β”‚  β†’ Use Babel for interop if needed                                 β”‚
β”‚                                                                     β”‚
β”‚  BROWSER-ONLY SCRIPT:                                               β”‚
β”‚  ────────────────────                                              β”‚
β”‚  β†’ ESM with <script type="module">                                 β”‚
β”‚  β†’ Or Vite for development with HMR                                β”‚
β”‚                                                                     β”‚
β”‚  AVOID:                                                             β”‚
β”‚  ──────                                                            β”‚
β”‚  β†’ AMD (obsolete)                                                   β”‚
β”‚  β†’ UMD (complex, declining)                                         β”‚
β”‚  β†’ IIFE for anything beyond small scripts                          β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Takeaways

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    ES MODULES SUMMARY                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                     β”‚
β”‚  THREE PHASES:                                                      β”‚
β”‚  1. Construction: Parse and build dependency graph                  β”‚
β”‚  2. Instantiation: Link exports and imports (live bindings)        β”‚
β”‚  3. Evaluation: Execute code depth-first, post-order               β”‚
β”‚                                                                     β”‚
β”‚  LIVE BINDINGS:                                                     β”‚
β”‚  β€’ Imports are references to exports                                β”‚
β”‚  β€’ Changes in exporting module are visible to importers            β”‚
β”‚  β€’ Read-only in importing module                                    β”‚
β”‚                                                                     β”‚
β”‚  CIRCULAR DEPENDENCIES:                                             β”‚
β”‚  β€’ Handled but may see undefined for uninitialized exports         β”‚
β”‚  β€’ Use functions for deferred access                                β”‚
β”‚                                                                     β”‚
β”‚  CACHING:                                                           β”‚
β”‚  β€’ Each module evaluated once                                       β”‚
β”‚  β€’ Same instance shared by all importers                           β”‚
β”‚  β€’ Natural singleton pattern                                        β”‚
β”‚                                                                     β”‚
β”‚  BEST PRACTICES:                                                    β”‚
β”‚  βœ… Use named exports for better tree-shaking                      β”‚
β”‚  βœ… Keep module side effects minimal                               β”‚
β”‚  βœ… Use dynamic import for code splitting                          β”‚
β”‚  βœ… Avoid circular dependencies when possible                       β”‚
β”‚  βœ… Use TLA sparingly (it blocks dependent modules)                β”‚
β”‚                                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Next Steps

Continue to 22.5 Performance & Optimization Internals to learn about optimization killers, deoptimization triggers, and how to write highly performant JavaScript.

README - JavaScript Tutorial | DeepML