lesson depth
Mastery
not started · 0%

Modern ESM & Tree-Shaking

ECMAScript module resolution, TypeScript bundler mode, and tree-shaking dead code elimination.

Freshness: current14 min readSoftware and Web Engineering

Key Learning Outcomes

  • Configure TypeScript for modern bundlers
  • Optimize static export graphs for tree-shaking

Mental model

ESM (import/export) evaluates static module dependency graphs before code execution, whereas CommonJS (require()) loads modules dynamically at runtime.

Static Import Declaration
Build Static Dependency Graph
Tree-Shaking Dead Code Elimination
Emit Bundled Output Asset
Conceptual teaching model synthesized from:TypeScript 5.4 Language Specification & Type System Mechanics

Theory

Because ESM imports must appear at top-level, modern bundlers (Vite, Rollup, Turbopack, esbuild) construct a static Abstract Syntax Tree (AST) graph of all exported symbols. Unreferenced exports are eliminated during dead code elimination (Tree-Shaking). In TypeScript 5.0+, setting moduleResolution: "bundler" aligns type resolution with modern web build tools.

typescript(11 lines)
1export function add(a: number, b: number): number {
2 return a + b;
3}
4
5export function unusedHeavyMath(x: number): number {
6 return Math.pow(x, 100);
7}
8
9import { add } from "./mathUtils";
10console.log(add(5, 10));

Alternatives and trade-offs

  • CommonJS (require): Supports dynamic path evaluation (require('./' + name)), but prevents static analysis and dead code elimination.
  • ESM (import): Static, tree-shakeable, and natively supported across modern browsers and Node.js 18+.

Failure modes and misconceptions

  1. Side-effect imports: Importing files with top-level side effects (e.g. import './polyfills') prevents bundlers from shaking those modules. Mark "sideEffects": false in package.json.
  2. CJS/ESM dual package hazard: Mixing CJS require and ESM import for the same library can load two separate singleton instances into memory.
Reflect before revealing the guide

Decision scenario

Configure TypeScript applications targeting modern bundlers (Vite, Next.js) with "moduleResolution": "bundler" and "sideEffects": false in library packages.

Learning outcomes

  • Contrast static ESM module graphs with dynamic CommonJS require paths.
  • Configure moduleResolution: "bundler" for modern frontend tooling.
  • Optimize export structures to enable tree-shaking dead code elimination.

Trade-offs

ESM enables aggressive tree-shaking and smaller production bundle sizes, but requires consistent package exports configuration across full-stack repositories.

Prerequisites & Related Concepts (2)

Private notes

0 words
Next