Documentation menu

Roadmap

Open questions

This document prevents provisional ideas from quietly becoming promises. Each question should eventually be resolved through an executable example, focused implementation, and explicit decision. Resolved behavior belongs in guides, reference pages, or an explicit current-state note; this page retains only the remaining design choice.

Route registration and nesting

Direction: router.addRoute(path, RouteConstructor) creates isolated server route graphs. A router createStores() factory supplies one typed named record to the routes in a graph; every server request receives fresh stores.

Open questions:

  • How are nested routes and layouts declared?
  • Which parent data should a child route inherit in addition to explicitly injected shared stores?
  • How are path parameters typed without repeating the path as a generic?
  • Can a package install a subtree with a configurable base path?
  • How does the client preserve parent route instances while replacing a child?

Acceptance criteria:

  • Registration remains explicit and inspectable.
  • Server state cannot leak between requests.
  • Plain anchors resolve to the same route tree as imperative navigation.
  • Nested loading and error boundaries have deterministic ownership.

View representation

Direction: Compiled .hbs imports are typed callable functions returning an opaque View. Their first argument is props, and their remaining View arguments render in order at the template’s single optional outlet.

Implemented today: A View is an immutable composition of a compiled template, props, and child views. Each compiled template contains a validated, frozen, versioned ViewProgram instruction sequence. renderToString() performs blocking server rendering without a DOM.

Open questions:

  • How should the current ViewProgram evolve to support streaming and client patches?
  • Should trusted HTML carry provenance beyond the explicit trustedHtml() wrapper?
  • What dedicated preview API is needed beyond renderToString() and route-level renderScreen()?

Acceptance criteria:

  • View functions remain cheap to compose.
  • Server rendering does not require a DOM.
  • Escaping is safe by default.
  • The representation supports blocking SSR, streaming, and client patches.

Styling and asset delivery

Direction: Goldar compiles top-level .hbs <style> blocks into scoped Vite CSS assets and leaves Shadow DOM styling to each custom element. <style is:global> and :global(...) are the explicit escape hatches.

Implemented today: Compiled blocks preserve source order, and the generated browser entry imports template styles in lexical template-path order. Scoped @keyframes are rejected with a source-located diagnostic; global keyframes remain available.

Open questions:

  • How should the current lexical template/block ordering integrate with global, layout, route, component, and transition layers?
  • How does the emitted template stylesheet graph become route-specific server <link> output?
  • When may a browser navigator remove a stylesheet that belonged to the previous route?
  • How should scoped keyframe names and animation references be rewritten together?
  • How are preload hints and content hashes represented in the route manifest?

Acceptance criteria:

  • Server rendering and client navigation use the same stylesheet manifest.
  • The next route is not revealed before its required styles are ready.
  • Ordinary light-DOM CSS follows browser cascade rules without runtime style injection.
  • Custom elements retain ownership of their Shadow DOM styles.
  • Unsupported or failed asset loads produce diagnosable navigation behavior.

Async views

Direction: AsyncView is a declarative node connecting a Data resource to loading, error, data, and revalidation views.

Open questions:

  • Are the final state names loading, error, data, and revalidating?
  • Does initial SSR block by default or stream by default?
  • How does container wrap changing state without rerendering unnecessarily?
  • What does the error callback receive besides error and retry?
  • How are timeouts and aborted loads represented?

Acceptance criteria:

  • Resource output is inferred from load().
  • Stale data can remain visible during refresh.
  • Retry uses Goldar resource state rather than calling load() directly.
  • One route implementation supports server and client rendering strategies.

Data caching

Implemented today: Each owned Data instance loads at most once per request resolution scope. Goldar has no cross-request cache; broader caching remains a future policy decision.

Open questions:

  • What cache-policy vocabulary should Goldar use?
  • Does no-cache follow HTTP semantics or colloquial framework semantics?
  • Is no-store available?
  • Which scopes exist: request, navigation, session, process, edge cache, persistent cache?
  • How are keys derived from params, query, headers, identity, and locale?
  • How do actions invalidate resource instances and shared cache entries?

Acceptance criteria:

  • Policy names have precise semantics.
  • Authenticated data cannot cross identity boundaries.
  • Refresh, invalidate, and revalidate are distinct where necessary.
  • Cache behavior is observable in development tooling.

Store reactivity

Direction: Authors read and assign ordinary class fields.

Open questions:

  • Does the compiler instrument assignments, does the runtime proxy stores, or is a hybrid required?
  • How are array and collection mutations observed?
  • How are derived values represented?
  • How are subscriptions scoped and disposed?
  • Which stores serialize from server to browser?
  • How long does a store survive client navigation?
  • Are method references automatically bound?

Acceptance criteria:

  • this.count += 1 updates dependent client views.
  • No .value, reducer, or explicit dispatch ceremony is required.
  • Server stores remain request-isolated.
  • Cleanup is deterministic.
  • Behavior remains understandable in ordinary TypeScript.

Named functions and hydration

Direction: Views receive named functions as ordinary props, while provenance determines how they execute.

Open questions:

  • How does the compiler identify the smallest client graph required by a local callback?
  • Can a callback hydrate only the custom element or view region that consumes it?
  • How are function identities preserved across rerenders?
  • Should Store methods be compiler-bound when passed directly?
  • How do development diagnostics explain a server-only closure used by client code?

Acceptance criteria:

  • Arbitrary closures are never serialized.
  • Local callbacks ship only the client code they need.
  • The no-JavaScript document remains useful.
  • Errors at server/client boundaries are compile-time diagnostics where possible.

Form actions

Implemented today: RouteContext.action(action) returns immutable route-local FormActionReference metadata for a standard POST form. RouteContext.submission(action) exposes preserved values and normalized field errors after invalid(). Authors explicitly return invalid, redirect, or success, or use a raw Response escape hatch. Same-origin CSRF protection is enabled by default and can be disabled application-wide.

Open questions:

  • How are schemas integrated without requiring one validation library?
  • How can exceptional endpoints customize origin or CSRF policy without disabling application-wide protection?
  • How should client enhancement add pending, interruption, and focus behavior without changing the implemented server dispatcher?

Acceptance criteria:

  • Standard forms work without JavaScript.
  • Enhanced forms run the same mutation and validation path.
  • Action identifiers cannot be forged into unrelated actions.
  • Validation failures preserve accessible form behavior.
  • Successful actions can invalidate concrete resources.

Direction: Plain anchors drive both document and enhanced navigation.

Open questions:

  • Is the navigator always present or emitted only when enhanced behavior is used?
  • What preload policies are supported?
  • How are route-level transition names declared?
  • Are transition names owned by routes, views, rendered elements, or an explicit combination?
  • How do forward, back, replace, and redirect navigation determine transition direction?
  • How are scroll, focus, hash targets, and browser restoration coordinated?
  • How does navigation behave when a custom element delays upgrade?
  • When is a route patch considered ready to commit after its critical data and styles resolve?
  • What happens when a second navigation interrupts loading, patching, or animation?
  • Which behavior changes when the user requests reduced motion?
  • Is cross-document transition support a separate later capability?

Acceptance criteria:

  • No <Link> component is required.
  • Browser-native click behavior is preserved.
  • Disabling JavaScript produces valid navigation.
  • View Transitions degrade cleanly when unsupported.
  • Reduced motion uses the same completed navigation without animation.
  • An interrupted or failed navigation never exposes a half-updated document.

Web Component registration

Implemented today: Any standards-compliant custom-element implementation can participate. The compiler records tags used by templates, and Vite maps each tag to one same-basename local module whose default export is the constructor. The components option overrides package modules and non-conventional layouts.

Open questions:

  • How should the discovery convention and explicit overrides evolve for richer metadata without making component implementations framework-specific?
  • Which loading policies are built in?
  • How are package-provided registries merged?
  • How are properties, listeners, slots, and events described to the template language service?
  • What optional SSR or Declarative Shadow DOM hooks exist?

Acceptance criteria:

  • Lit and vanilla implementations work without adapters.
  • Duplicate tag names fail early where detectable.
  • Unregistered markup remains meaningful before upgrade.
  • Component code can be split by route and loading policy.

Template binding syntax

Direction: Templates look like HTML and preserve distinctions between attributes, properties, events, and children. outlet remains a special structural binding for rendering a view’s ordered child views.

Implemented today: Bound false, null, and undefined omit an attribute; true emits a presence-only attribute; strings and numbers serialize with escaping. Objects and functions fail instead of being stringified.

Open questions:

  • How does syntax distinguish property assignment from attribute serialization?
  • How are event listeners written?
  • How are named functions and server capabilities typed?

Acceptance criteria:

  • Common HTML remains plain HTML.
  • Objects and functions are never accidentally stringified.
  • Custom-element types power completion and diagnostics.
  • Syntax remains readable without framework-specific ceremony dominating the markup.

Hono boundary

Implemented today: Goldar Core depends directly on Hono. ApplicationOptions.server(hono) runs once before Goldar routes are registered, and generic Hono environments carry typed bindings through route, data, and form-action contexts. Global middleware ordering is defined; routine code can remain framework-oriented while retaining direct Hono access.

Open questions:

  • Should a future portable platform context supplement or narrow the current Hono context access?
  • Which responsibilities should remain in Core versus deployment adapters?
  • How should route-specific middleware be expressed?

Acceptance criteria:

  • Hono middleware remains fully usable.
  • Application code can remain platform-oriented.
  • Server-only Hono types do not force Hono into browser bundles.
  • Runtime-specific bindings are typed and explicit.

Compiler and configuration

Implemented today: goldar build and goldar dev discover a default-exported application at src/index.* when no config exists. Project-root public/ is the conventional static-asset directory, and applications keep tests beneath tests/. An explicit entry bypasses convention and config discovery. For entryless commands, --config or a discovered goldar.config.* takes precedence and configures custom build, development, and supervised start commands. Builds emit dist/goldar-manifest.json, generated template types, and per-file size reporting.

Open questions:

  • Should future compiler and deployment settings extend the current command-orchestration GoldarConfig, or use a separate configuration boundary?
  • How should the existing build manifest evolve to connect routes, views, resources, actions, and component chunks?
  • What inspection tooling is needed beyond the build manifest, generated declarations, and build size report?

Acceptance criteria:

  • A one-file application is first-class.
  • Any folder organization can express the same graph.
  • Discovery and explicit registration behave identically.
  • Compiler output is inspectable and deterministic.