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

  1. Every AST node carries a source range, from lexing onward. Positions cannot be recovered later.
  2. A static hoist must be genuinely static — no reads of anything dynamic.
  3. A patch flag must be a superset of what can change. Under-flagging is a correctness bug.
  4. Generated code must be debuggable, which means composable source maps at every stage.

Why compiler optimisation is riskier than it looks

OptimisationSilent failure if wrong
Static hoistinga hoisted node mutates and is shared across instances
Patch flagsdynamic node marked static ⇒ update never appears
Static prop dedupa mutated shared object leaks between instances
Tree flatteninga 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.