Notifications

No notifications

/Phase 3

Modules — ESM & CommonJS

Modules let you split code across files and explicitly say what's public. Modern JS uses ES Modules (ESM) with import / export everywhere — browsers, Node, Vite, Next.js. Older Node code uses CommonJS with require / module.exports. This page covers both, named vs default exports, dynamic import(), and how Node + bundlers actually resolve a path like "react".

On this page

Detailed Theory

# Modules

ES Modules (ESM) — the standard

File: math.js
// named exports — many per file
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export class Vec { /* … */ }

// default export — at most one per file export default function multiply(a, b) { return a * b; }

File: app.js

import multiply, { PI, add } from "./math.js";   // default + named
import { add as plus } from "./math.js";          // rename
import * as math from "./math.js";                // namespace import

Re-export (barrel files)

// index.js
export { add, PI } from "./math.js";
export { default as multiply } from "./math.js";
export * from "./other.js";

Dynamic import — returns a Promise

Useful for code splitting / loading on demand.
const mod = await import("./heavy.js");
mod.run();

// React.lazy uses this under the hood const Chart = React.lazy(() => import("./Chart"));

Top-level await (in modules)

// data.js — works at module top level
const data = await fetch("/api").then(r => r.json());
export default data;

How modules are different from regular scripts

featurescriptmodule
Strict modeopt-inalways on
Top-level thiswindowundefined
Top-level var is globalyesno
Each import evaluated oncen/ayes (cached)
HTML script tag