Findings No. 63
Effect costs about 15 kB gzip per page, so keep it out of anything the root layout or client hooks import
Effect added a 15.1 kB gzip chunk to CCRTA's map pages only. What the root layout or client hooks import loads everywhere, so shared helpers stay Effect-free.
CCRTA's Effect pilot converted map loading and the live polls on the map pages. In a production build, Effect landed as one shared chunk of 15.1 kB gzip. Each converted page's own JavaScript grew by 15.2 to 15.7 kB gzip; /bus-tracker, for example, went from 15.6 kB to 31.3 kB. Because the chunk is shared, a rider downloads it once across the map pages and the browser caches it. It was not in the shared entry, so pages without a map did not load it. The entry itself measured 2.0 kB larger, and that came from Rollup regrouping small shared chunks rather than from Effect code.
That boundary holds only as long as nothing every page loads imports Effect. Code imported by the root layout or by hooks.client.ts ships on every page. Two decisions followed. The page-data retry wrapper retryDataFetch is installed in hooks.client.ts, so it was left unconverted: the adoption notes estimate converting it would add about 15 kB to every page, for a wrapper that was already correct and tested. A day later, a fix for Vercel Bot Protection challenges needed a banner in the root layout plus a helper shared with the Effect poll code. That helper went into its own module, challenge.ts, which imports Sentry and no Effect. The poll code in resilience.ts imports from it, and the banner component imports only its event name.
Keep the modules that the root layout and client hooks import free of large libraries. When a helper has to be shared with Effect code, put it in a small separate file that both sides import, and compare per-page sizes in a production build before and after.
Receipt: CCRTA Website commits f9e61e0 and 78bb778 (src/lib/client/effect/resilience.ts, src/lib/client/challenge.ts, src/routes/+layout.svelte; docs/effect-adoption.md "Pilot results").