ES Modules
Files as isolated, statically-analysable units -- named and default exports, imports, and dynamic loading.
Syntax
export const x = 1;
export default fn;
import def, { x } from './mod.js';
const m = await import('./mod.js');ES modules give every file its own scope and a declared public surface. Names are private unless exported; you pull in exactly what you need with import.
// math.js
export const PI = 3.14159;
export function area(r) { return PI * r * r; }
export default function circumference(r) { return 2 * PI * r; }
// app.js
import circumference, { PI, area } from './math.js';
import * as math from './math.js';What makes modules special
- Static structure -- imports/exports are resolved before execution, enabling tree-shaking and clear dependency graphs.
- Live bindings -- an imported name reflects the exporter's current value, it is not a copy.
- Always strict, always deferred, each loaded once and cached.
Dynamic import
import('./heavy.js') returns a promise, so you can load code on demand -- the basis of route-level code splitting.
Example
Loading editor…
Press Run to execute the code.
When to use it
- Split a large utility file into focused modules and import only the functions each consumer needs.
- Re-export third-party symbols from a single adapter module so the rest of the codebase has one import point.
- Use dynamic import() to lazy-load a heavy chart library only when the user opens the analytics page.
More examples
Named export and import
Exports named members from math.js and imports only the ones needed in main.js.
// math.js
export function add(a, b) { return a + b; }
export const PI = 3.14159;
// main.js
import { add, PI } from "./math.js";
console.log(add(2, 3)); // 5
console.log(PI); // 3.14159Default export and import
Uses a default export for a module's primary function, imported without braces under any chosen name.
// logger.js
export default function log(msg) {
console.log("[LOG]", msg);
}
// app.js
import log from "./logger.js";
log("App started"); // [LOG] App startedDynamic import for lazy loading
Loads the charts module on demand only when the user clicks the button, reducing the initial bundle size.
document.getElementById("charts-btn").addEventListener("click", async () => {
const { renderChart } = await import("./charts.js");
renderChart("#canvas", data);
});
Discussion