- Shipped
- 19 Agosti 2026, 06:54 UTC
- Author
- Kamo
- Commit
- 4fae924
The locale layout resolved its messages with a bare getMessages(), which reads request headers and so opted the ENTIRE app out of static rendering. With no loading.tsx anywhere, Next had nothing to prefetch a dynamic route up to: a <Link> prefetch came back as 220 bytes carrying the route tree and not one segment or chunk reference. Every click then started cold — fetch the payload, parse it to discover which JS the page needs, fetch that, mount, paint — with the previous page frozen on screen for the whole chain and no feedback of any kind. kamo-internal does strictly more work per page and feels instant because it has app/loading.tsx. setRequestLocale() before getMessages() puts the tree back on the static path; 187 of 189 routes prerender now. The two KB routes stay per-request on purpose and say why. Nine force-dynamic lines go with it: six were the documented workaround for this exact call (they cited DYNAMIC_SERVER_USAGE by name), and pricing, offer, calculator and changelog already carried next:{revalidate} on their own fetches, so rendering per request bought no freshness — it only threw away the fetch cache. Prefetching whole pages then made the message bundle the next problem: 146 KB of JSON rode along on every link in the viewport, ~40 KB gzipped of it identical between them. Only eight namespaces are read by shared components; every other one belongs to exactly one route, so each route now carries its own through a layout of its own. A nested provider REPLACES its parent's messages rather than merging with them, which is why the global set is repeated rather than inherited. Measured against a production build: prefetch 220 B / 0 chunk refs -> 8-16 KB gzipped / 74, and /en/features' HTML 247,793 -> 121,537 bytes. All 181 prerendered pages were scanned for unresolved message keys — the only three found predate this change and belong in the dictionary, not here.