Skip to content

Frontend & UI

Frontend in depth

A correct mental model for React Server Components, server state with TanStack Query, type-level TypeScript, proper ARIA widgets, Web Workers, real-user observability and micro-frontends — the hard parts under the framework surface.

7 parts129 min readUpdated Sep 20, 2026

Parts

  1. Part 1

    A Correct Mental Model for React Server Components: Two Module Graphs, One Boundary

    "use client" doesn't mark a kind of component; it marks where the client graph begins. This post rebuilds the mental model for RSC in Next.js 16: what crosses the boundary, where data fetching belongs, waterfalls, streaming, and the mistakes that bloat bundles or leak data.

    18 min

  2. Part 2

    Server State Is a Cache, Not State: TanStack Query v5 in Depth

    Data from the server isn't yours — you only hold a copy with an expiry date. This post goes deep on TanStack Query v5 through the lens of caching: query key design, staleTime and gcTime, invalidation, optimistic updates with rollback, Suspense, hydration with the Next.js App Router, infinite queries, and when not to use it.

    17 min

  3. Part 3

    Type-Level TypeScript for API Contracts You Can't Misuse

    Conditional types and infer, key remapping, template literal types that turn "/users/:id/posts/:postId" into typed params, a fetch client derived from a route map, typed errors, branded IDs, satisfies and const type parameters, a Zod bridge so the types aren't lies — and when to stop.

    16 min

  4. Part 4

    Accessible Custom Widgets in React: ARIA Patterns That Actually Work

    When native elements run out, ARIA is a contract you have to keep. The accessibility tree and name computation, roving tabindex vs aria-activedescendant, a combobox and tabs built step by step, live regions that really announce, focus on route changes, and how to test it all.

    20 min

  5. Part 5

    Getting Work Off the Main Thread: Web Workers, Transferables, SharedArrayBuffer and Worker Pools

    Web Workers aren't magic for every slow page. This post covers when moving work to a worker pays off, what structured clone really costs, transferables, SharedArrayBuffer and COOP/COEP, a hand-written Comlink-style RPC, bundler setup, worker pools, cancellation with AbortSignal, real examples and alternatives like scheduler.yield.

    17 min

  6. Part 6

    Frontend Observability in Practice: RUM with web-vitals, Private Source Maps and Browser-to-Backend Traces

    Installing Sentry is only step one. This is how I build real frontend observability: lab vs field data, RUM with web-vitals attribution, beacons that don't get lost, sampling, private source maps, taming noisy errors, linking traces to the backend with traceparent, PII scrubbing, p75 dashboards and deploy markers.

    21 min

  7. Part 7

    Micro-frontends, Honestly: When They're Worth It, How Module Federation 2.0 Works, and What They Cost

    Micro-frontends solve an organizational problem — independent teams shipping independently — not a technical one. This post compares five ways to compose a frontend, digs into Module Federation 2.0 (shared singletons, version skew, manifests, types, fallbacks) and shows when a Turborepo monorepo is the better answer.

    20 min

Series review

0/14 answered · 0 correct

14 questions drawn from the parts of this series. Answers here count toward each post's own quiz.

  1. Question 1 of 14IntermediateIn the two-module-graph model, what does "use client" actually mean?
  2. Question 2 of 14IntermediateA ReviewsDrawer (client, with open/close state) must show Reviews, an async Server Component that reads the DB. What is the right approach?
  3. Question 3 of 14IntermediateHow do staleTime and gcTime differ in TanStack Query v5?
  4. Question 4 of 14AdvancedWhy should you not use a module-scope QueryClient on the server (Next.js)?
  5. Question 5 of 14IntermediateWhat is the design goal of the route map in the post, and what does it give you when someone renames an endpoint's path?
  6. Question 6 of 14AdvancedYou declare const routes: RouteMap = { ... } and notice client calls never require params. What is the cause and the fix?
  7. Question 7 of 14StarterA colleague writes a div with role="button" and an onClick, assuming that makes it accessible. What is missing?
  8. Question 8 of 14IntermediateWhy does a typeable combobox use aria-activedescendant instead of roving tabindex to move through suggestions?
  9. Question 9 of 14IntermediateYou moved CSV parsing into a Web Worker, but the page still freezes for almost half a second when the worker sends the result (two hundred thousand objects) back. What is the main cause?
  10. Question 10 of 14StarterYour page is slow because React has to render a list of ten thousand rows. Should you move this work into a Web Worker?
  11. Question 11 of 14StarterLighthouse reports an LCP of 1.2 s while Search Console (CrUX) reports 3.8 s. How does the post say to read this?
  12. Question 12 of 14IntermediateHow should you avoid losing CLS and INP when the user closes the page?
  13. Question 13 of 14IntermediateA two-person team says "let's split into micro-frontends to make the app faster and builds quicker". Which assessment matches the post?
  14. Question 14 of 14AdvancedWhy must React and React DOM be declared shared singletons in Module Federation, and what happens if you forget one of them?

Other series

Series