fw-06 — Analysis
The asymmetry that justifies compilers
A template is statically analysable; a render function generally is not. Everything a compiler-first framework does better follows from that one fact.
A template compiler can determine without running anything: which subtrees are fully static, which specific attributes are dynamic, the tree's shape, which variables an expression references, whether a key expression is stable.
A JSX/JS render function cannot, wherever the code is opaque — and the compiler must be conservative exactly where it cannot prove a fact, which costs precisely the optimisation you wanted.
That is why React's compiler arrived a decade after Vue's: it had to become a whole-function analysis with escape hatches rather than a template transform.
Required invariants
- Every AST node carries a source range, from lexing onward. Positions cannot be recovered later.
- A static hoist must be genuinely static — no reads of anything dynamic.
- A patch flag must be a superset of what can change. Under-flagging is a correctness bug.
- Generated code must be debuggable, which means composable source maps at every stage.
Why compiler optimisation is riskier than it looks
| Optimisation | Silent failure if wrong |
|---|---|
| Static hoisting | a hoisted node mutates and is shared across instances |
| Patch flags | dynamic node marked static ⇒ update never appears |
| Static prop dedup | a mutated shared object leaks between instances |
| Tree flattening | a dynamic descendant is missed |
Every failure is a correctness bug presenting as "the UI didn't update" — no error, no stack trace pointing at the compiler. A slow program is annoying; one that silently shows stale data is a data-integrity incident.
The testing strategy that follows: run the same suite with optimisations on and off and compare.
That is Chromium's virtual-test-suite idea (bi-13) applied to a compiler.
Error messages are the product
A caret-and-line error takes five seconds to act on; Cannot read properties of undefined takes
twenty minutes and teaches distrust. A compiler's error messages are the majority of its user
interface — which is why source ranges are step 2 of the build order, not an afterthought.