Skip to content

Node Development by Restart

Current exploration

This page defines the development boundary for the experimental Node namespace model. It is not an ivue package feature.

A runtime should own only the problems the host runtime does not already solve.

The Node namespace model solves authoring structure: circular dependencies resolve late, static methods are passable, inheritance remains native, and boot composition selects one class. A normal Node watcher already solves the remaining development event by restarting the process after an edit.

text
edit
→ watcher stops the process
→ Node loads one fresh module graph
→ namespaces compose
→ routes retain methods from that generation
→ application runs

The production and development application execute the same class paths. The watcher changes process lifetime, not class semantics.

Why this already improves class reload

Class-heavy module graphs often fail before an application can restart cleanly. An eager cross-module class read observes an uninitialized binding, or a static initializer performs work before its dependency exists.

The namespace grammar removes those eager value edges:

ts
static get Users() {
  return Users.Class;
}

Imports may remain circular because dependency values are read only when behavior runs. A fresh Node process can therefore evaluate the graph in any module order permitted by the same late-read invariant.

Normal restart is not a fallback around broken class modules. The namespace shape makes normal restart dependable again.

The cost of keeping the process alive

Live class HMR inside Node requires much more than assigning a new constructor. A complete system must own:

  • file watching and transitive module invalidation;
  • stable identities across re-evaluated module namespace objects;
  • transactional evaluation and rollback;
  • plugin recomposition against each new foundation;
  • callbacks already retained by routers, queues, and emitters;
  • active asynchronous frames from the previous generation;
  • explicit reconstruction and disposal of stateful instances;
  • static initialization, native private brands, and top-level side effects;
  • a cold-start verification path that catches hidden startup failures.

That machinery becomes a second module runtime. It has its own correctness surface, tests, compatibility constraints, and maintenance cost. The namespace pattern makes such a runtime possible, but possibility does not make it part of the minimal backend contract.

One generation is the coherence boundary

A process restart keeps constructor wiring, static fields, closures, inheritance, private brands, retained callbacks, and process-owned resources within one evaluated generation. No old object receives behavior from a new declaration.

This is the same ownership principle used by ivue development: the framework or process owner reconstructs the owning boundary. The class transform does not implement a parallel replacement engine.

Resource lifetime remains explicit

Restart discards in-memory resources. Development applications should make their important state reproducible through fixtures, external databases, seeded sessions, or explicit boot scripts.

Some systems have multi-minute warmup, irreplaceable in-memory investigations, or long-lived connections that make process preservation unusually valuable. Those systems may justify a managed module runner. That is a separate product with explicit resource, dispatch, and state-migration contracts. It is not a hidden obligation of every class module.

The reduction boundary

CapabilityOwner
Circular-import safetyNamespace getters and late method bodies
Passable static callbacksStatic() first-read binding
Inheritance and superRaw $Class declarations
Plugin selectionBoot-time kernel composition
Source-file watchingExisting Node development tool
Code replacementProcess restart
Durable stateExternal resource owner
Request-varying provider choiceExplicit context or scoped DI

Removing live HMR preserves every selected capability. Adding it would expand scope without strengthening the namespace invariant.

The retained possibility

The namespace's stable object and mutable Class slot remain useful seams for tests and boot-time plugins. They also provide the canonical identity a future live runtime would require. Nothing in the reduced design prevents a separate system from exploring that direction.

The default remains smaller:

text
namespace + late getters + Static() + restart

The Namespace Pattern explains the cross-runtime invariant. Static() — Capability Classes contains the working transform, tests, benchmarks, and exact scope.

Released under the MIT License.