Motivation
Deferred shell branches shipped in 0.21.0-dev.1 (KaiselBranch.deferred(loadLibrary: feature.loadLibrary)) — a tab's code loads on first activation, with errorBuilder + retry. But deferral is only available at branch granularity. A heavy route on the main stack (an editor, a report viewer, an admin area) still ships in the initial bundle even if most users never open it. On Flutter web that's paid in initial JS download; on Android it blocks using deferred components per feature.
Proposal
First-class per-route deferral with parity to what branches already have:
import 'package:app/editor/editor.dart' deferred as editor;
builder: (context, route) => switch (route) {
EditorRoute() => KaiselDeferredScreen(
load: editor.loadLibrary,
builder: (context) => editor.EditorScreen(),
// loadingBuilder / errorBuilder with retry, matching KaiselBranch.deferred
),
...
},
Design questions
- Deep links & restoration: a URL/restored stack landing directly on a deferred route must trigger the load before first build — the loading state appears inside the route's page, not as a blank app.
- Transitions: pushing a deferred route ideally delays the page transition until the library resolves (or animates into the loading state — decide which default).
- Guards: guards run on values, so they need no code from the deferred library — worth stating as a guarantee.
loadLibrary caching: Dart already memoizes it; the widget just needs idempotent handling.
Non-goals
Automatic inference of what to defer — the deferred as import stays an explicit app decision, same as branches.
Motivation
Deferred shell branches shipped in 0.21.0-dev.1 (
KaiselBranch.deferred(loadLibrary: feature.loadLibrary)) — a tab's code loads on first activation, witherrorBuilder+ retry. But deferral is only available at branch granularity. A heavy route on the main stack (an editor, a report viewer, an admin area) still ships in the initial bundle even if most users never open it. On Flutter web that's paid in initial JS download; on Android it blocks using deferred components per feature.Proposal
First-class per-route deferral with parity to what branches already have:
Design questions
loadLibrarycaching: Dart already memoizes it; the widget just needs idempotent handling.Non-goals
Automatic inference of what to defer — the
deferred asimport stays an explicit app decision, same as branches.