ES Modules

Files as isolated, statically-analysable units -- named and default exports, imports, and dynamic loading.

Syntaxexport 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

Try it yourself
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.

Example · 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.14159

Default export and import

Uses a default export for a module's primary function, imported without braces under any chosen name.

Example · js
// logger.js
export default function log(msg) {
  console.log("[LOG]", msg);
}

// app.js
import log from "./logger.js";
log("App started"); // [LOG] App started

Dynamic import for lazy loading

Loads the charts module on demand only when the user clicks the button, reducing the initial bundle size.

Example · js
document.getElementById("charts-btn").addEventListener("click", async () => {
  const { renderChart } = await import("./charts.js");
  renderChart("#canvas", data);
});

Discussion

  • Be the first to comment on this lesson.
ES Modules — JavaScript | SoundsCode