Tree-shaking, the horticulturally misguided algorithm (2023)
Developers debate the term “tree-shaking” versus the older “dead code elimination,” arguing over whether the newer, JavaScript-driven metaphor accurately describes the process of removing unreachable code and data from programs. From there the conversation broadens to WebAssembly’s chronic code-size problem: languages often ship their own runtimes and standard libraries, prompting techniques like aggressive reachability analysis, careful Rust coding patterns, and tools such as `wasm-opt` and Brotli compression to shrink binaries. Participants also explore longer‑term ideas like dynamic linking and shared language runtimes in the browser, as well as the trade‑offs of using Wasm for DOM-heavy or GUI-style applications compared to JavaScript.
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-optand 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.