From 932821beb5a4595c63fa8800d18482e3ebaa75e9 Mon Sep 17 00:00:00 2001 From: Jon Laing Date: Fri, 24 Jul 2026 14:06:45 -0400 Subject: [PATCH] fix: Outlet's SPA fallback honours Route.static's load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fallback branch only checked route._loader and route._handlers. Route.static sets neither — its loader lives inside _staticConfig.load. So hasHooks was false, the fallback block was skipped, and routeData stayed at its default with data: undefined. route.render(undefined) then crashed on any static-route render that touched its data arg. Fallback now also runs _staticConfig?.load when present. Fixes Route.static in pure-SPA mode; also stops 'provider dropped through unexpectedly' cases from presenting as opaque 'Cannot read properties of undefined' errors from user code. Co-Authored-By: Claude Opus 4.7 --- .changeset/outlet-static-route-fallback.md | 7 +++++++ packages/router/src/Outlet.ts | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 .changeset/outlet-static-route-fallback.md diff --git a/.changeset/outlet-static-route-fallback.md b/.changeset/outlet-static-route-fallback.md new file mode 100644 index 0000000..4e29db9 --- /dev/null +++ b/.changeset/outlet-static-route-fallback.md @@ -0,0 +1,7 @@ +--- +"@effex/router": patch +--- + +Fix `Outlet`'s SPA fallback (no `RouteDataProvider` in context) to honour `Route.static`. The fallback branch only checked `route._loader` and `route._handlers` — `Route.static` puts its loader inside `_staticConfig.load` and sets neither of those, so `hasHooks` was `false`, the branch was skipped, and `routeData` stayed at its default with `data: undefined`. `route.render(undefined)` then crashed on any static-route render function that touched its `data` argument. + +Now the fallback also runs `_staticConfig?.load` when present. `Route.static` routes work correctly in pure-SPA mode (no `@effex/platform`), and the "provider dropped through unexpectedly" cases stop presenting as opaque `Cannot read properties of undefined` from user code. diff --git a/packages/router/src/Outlet.ts b/packages/router/src/Outlet.ts index 6aad8cd..b973693 100644 --- a/packages/router/src/Outlet.ts +++ b/packages/router/src/Outlet.ts @@ -126,17 +126,27 @@ const renderRouteWithGuard = ( return yield* $.div(); } } else { + // SPA fallback: no data provider in context (e.g. SPA-only app, or a + // component tree with a data provider bypassed). Run whichever loader + // the route has directly. Route.get sets `_loader`; Route.static puts + // its loader inside `_staticConfig.load` — both need to be honoured or + // the route's render will receive undefined data and crash. + const hasLoader = + route._loader != null || route._staticConfig?.load != null; const hasHooks = - route._loader || (route._handlers && route._handlers.length > 0); + hasLoader || (route._handlers && route._handlers.length > 0); if (hasHooks) { - // Default: run the loader directly, compute action paths const data = route._loader ? yield* route._loader({ params: currentMatch.params, searchParams: searchParamsObj, }) - : undefined; + : route._staticConfig?.load + ? yield* route._staticConfig.load({ + params: currentMatch.params, + }) + : undefined; const actions: Record = {}; for (const h of route._handlers) {