Files
TREK/client/src/mobile/components/MRouteFallback.tsx
T
Maurice 057d4ba503 perf(client): pick the viewport branch at the route (#1817)
Every page imported its mobile screen statically and chose while rendering, so
each route chunk carried both trees and the viewport only decided which half
stayed dark. Worse, because ten route chunks shared the mobile tree, rollup
hoisted it into the entry chunk — so every desktop user downloaded the whole
mobile shell before seeing a single page.

The branch now decides the chunk. A phone never fetches the desktop planner, a
desktop never the mobile shell.

  entry chunk        1,243 -> 581 kB   (gzip 349 -> 177)
  TripPlannerPage      914 -> 340 kB
  VacayPage            361 ->  57 kB
  AdminPage            413 -> 225 kB
  SettingsPage         259 -> 155 kB

Splitting inside each page instead was measured and rejected: it leaves the
desktop code in the same module as the switch, so a phone would still download
it and then wait for a second, serial request on top — 914 kB and a waterfall
against 550 kB in parallel.

The pass-through wrapper in each page stays deliberately. check-page-pattern
scans from the default export to the next top-level function and rejects hooks
there; making the desktop component the default export fails it immediately on
dashboard, planner and atlas.

RouteFallback gets a mobile face. It renders above MobileShell, so the --m-*
tokens do not resolve for it and the desktop spinner on bg-surface would be a
foreign white sheet in front of the mobile screen.

The five scattered viewport spot checks are replaced by one contract covering
all eleven routes, which is where the switch now lives.
2026-08-07 11:51:37 +02:00

20 lines
859 B
TypeScript

/**
* Placeholder while a route chunk is in flight — the phone counterpart to
* RouteFallback in App.tsx. It carries m-root itself, because it renders outside
* MobileShell and the --m-* tokens would not resolve otherwise.
*
* An outline rather than a spinner: on a phone an empty screen is the loudest
* state the app has, and a pulsing silhouette of what is about to arrive reads
* as "loading" instead of "broken".
*/
export default function MRouteFallback() {
return (
<div className="m-root flex h-dvh flex-col gap-3 px-4 pt-14 bg-[color:var(--m-bg)]">
<div className="h-7 w-40 animate-pulse rounded-lg bg-m-card" />
<div className="h-28 animate-pulse rounded-xl bg-m-card" />
<div className="h-28 animate-pulse rounded-xl bg-m-card" />
<div className="h-28 animate-pulse rounded-xl bg-m-card" />
</div>
)
}