Chapter 11

Loader & HMR (§5.2)

11.1 Entries and reconciliation

Definition 81 — entry

{ id, url, isolate, intercept, config, disabled }. An entry is a faithful specification because the support set (Def 74) reads only τ, π, d, p, and the entry gives all four: disabled → τ, tree position → π, url → the component and hence d, p.

Reconciliation is per field, least disruptive first: id/url rebuild; isolate reassigns realms (Algorithm 7, using per-key delimiter tags to tell "this binding is the entry's own and must move with it" from "shared realm, leave it"); intercept updates in place (read at access time, no reload); config is handed to the component, which typically diffs and reloads only on a material change — an @cordisjs/group entry's config is its child list, so group reconciliation is a keyed diff over child ids recursing into this same dispatch; disabled unloads / reloads. The metatheory is what makes this sound: Thm 80 (endpoint is a function of the final config), Thm 73 (it gets there), Cor 69 (a rebuilt entry leaves its neighbours alone), Thm 70 (no load order to arrange — modules can be fetched concurrently and activate when satisfied).

@cordisjs/group and @cordisjs/include (YAML/JSON subtrees) are ordinary components using instantiation (Def 52), so nested config trees stay inside the calculus.

11.2 Hot module replacement

  1. Classify the changed modules' import subgraph by fixed point: accepted once one import is accepted, declined once all are declined; anything caught in a cycle defaults to declined.
  2. Detect stale entries: an entry is stale iff its transitive imports (bounded by declined) meet accepted.
  3. Transactional reload: invalidate accepted modules' caches with backup; for each stale entry dispose the fiber and ctx.use(import(url)) afresh; on any import error restore caches and rebuild every stale entry from backup.

No import.meta.hot.accept boundaries are needed because a fiber already bounds all of its component's effects and coeffects. Cache eviction is Node-only (CommonJS require.cache plus engine-internal ESM hooks; ESM has no public API).

Olai

Bun lacks an ESM cache-bust, so the spike deferred HMR. Nothing in the theory depends on it — HMR is dispose + reinstantiate per stale entry — so deferring costs no guarantee. The YAML tree with patches/overlays/per-field reconciliation replaces the three arrays that today need manual sync.