Tree-shaking, the horticulturally misguided algorithm (2023)

Tree-shaking vs. Dead Code Elimination (DCE)

  • Strong debate over terminology. Some argue “tree-shaking” is a confusing misnomer and that “dead code elimination” or “reachability analysis” are clearer, long‑established terms.
  • Others defend “tree-shaking” as evocative, widely adopted (especially in JS), and semantically distinct: often used for bundler‑level, inter‑module pruning based on dependency graphs, while “DCE” is used for compiler/engine‑level, often intra‑function optimizations.
  • Historical notes: early “treeshakers” in Lisp (and possibly Smalltalk) operated on whole images, removing unused code and data, not just functions. Some argue this broader scope justifies a distinct term.
  • Several commenters insist the operations are conceptually the same; others maintain that granularity and tooling differences justify two names.

Wasm Code Size and Practical Optimization

  • Consensus that Wasm often suffers from large code size, problematic for initial page load and serverless cold starts.
  • Techniques reported to reduce size (mostly in Rust/Wasm):
    • Avoid floats, HashMaps, and strings when possible; use fixed point and vectors.
    • Minimize generic type diversity to avoid monomorphization bloat.
    • Use small allocators and strict size‑oriented compiler settings (e.g., opt-level="z", LTO, single codegen unit).
    • Post-process with wasm-opt and serve with Brotli compression.
  • Some think shrinking from ~700KB to ~400KB is only marginally useful on the web; others see it as an important counterexample to perceptions that Wasm apps are inevitably bloated.
  • Rust’s formatting/dbg! and standard library can inject surprising size overhead. WasmGC is seen as a way to cut runtime/allocator bulk, with current best results cited for Java/Kotlin.

Dynamic Linking and Shared Runtimes

  • Proposed long‑term fix: treat language runtimes as dynamically linked Wasm modules shared across apps.
  • Example: a single Pyodide runtime can be shared across many serverless workers.
  • Vision: browsers (or platforms) pre‑load popular runtimes/libraries so individual apps don’t ship them each time.
  • Concerns raised:
    • Cache partitioning and fingerprinting/privacy issues.
    • Version explosion and ABI stability; would require strong backward compatibility or curated, limited sets of versions.
    • Governance questions over which runtimes get “blessed” and preloaded.
  • Ideas floated: profile‑guided tree‑shaking plus on‑demand downloading of rarely used code, but risk of missing rare paths is noted.

Wasm, DOM Access, and GUI Models

  • Current reality: DOM and Web APIs are exposed to JS, so Wasm typically calls through JS “glue.” GC‑based references (WasmGC, component model) are expected to make direct DOM interaction more feasible.
  • Some argue that bypassing DOM/JS to render entirely via canvas/WebGL/WebGPU (for “native‑style” apps) is attractive; others counter this sacrifices accessibility and browser‑provided UI primitives, effectively “building a browser inside the browser.”
  • There is disagreement over whether Wasm should mainly supplement JS (e.g., heavy compute, workers) or be a full replacement for JS in front‑end development.

Wider Role and Design of Wasm

  • One camp sees Wasm as a deliberately minimal, secure, capability‑based “MVP” ISA, expected to grow features (GC, better host bindings).
  • Another camp finds it underpowered compared to classic VMs (no built‑in GC/stdlib or trivial DOM hooks), questioning its value for general web apps and some edge/FaaS scenarios.
  • Despite skepticism, multiple real uses are cited (games, RL libraries, map/earth viewers, Blazor, Flutter font/icon shaking), and some languages (e.g., OCaml, Zig) are viewed as promising for ultra‑small Wasm outputs.