Loading article...
Fetching the blog content...
Loading article...
Fetching the blog content...
Local-first systems and CRDTs, monorepo tooling, server-driven UI, microfrontends, WebGL/WebGPU, WebAssembly, and browser internals — the expert tier where architecture and platform machinery meet. Part 4 of the Frontend Roadmap series.
This tier is mostly architecture and the machinery under the platform. Few people work across all of it daily — the bar is understanding the model and the tradeoffs, not having shipped each one.
Local-first inverts the usual model. Instead of the server being the source of truth and the client a cache, the device holds a full primary copy of the data and the network is an enhancement, not a requirement. Offline parity means the app is fully functional offline, reads and writes both — not a degraded read-only mode. Changes happen locally and instantly, then sync in the background when connectivity returns.
The framing (from Ink and Switch's local-first essay) is a set of ideals: the app is fast because there is no network round trip in the interaction loop, it works offline, it is collaborative across devices and users, the user owns their data, and data is long-lived independent of any one server. The hard engineering problem is sync and merge.
A CRDT (Conflict-free Replicated Data Type) is a data structure designed so that concurrent edits made on different devices can be merged automatically and deterministically, with no central coordinator and no conflicts. Every replica that has seen the same set of changes converges to the same state, regardless of the order it received them.
Two families:
Concrete examples build intuition: a G-Counter (grow-only counter) keeps a per-replica count and merges by taking the max. An OR-Set (observed-remove set) tags each add with a unique id so concurrent add and remove resolve sensibly. Text editing uses sequence CRDTs (RGA and similar) that give every character a stable identity so concurrent insertions interleave deterministically.
The tradeoff against Operational Transformation (OT), what Google Docs historically used: OT requires a central server to transform operations against each other. CRDTs need no central authority — which is what makes true peer-to-peer collaboration possible — but pay in metadata overhead: all those unique ids and tombstones for deleted items accumulate. The practical libraries are Yjs and Automerge.
Optimistic replication applies a change locally and immediately, assuming it will succeed, then propagates it and reconciles later. It is the engine behind local-first sync and the everyday optimistic UI pattern: update the interface the instant the user acts, fire the request in the background, and roll back if it fails.
The model accepts eventual consistency: replicas may diverge briefly and converge once changes propagate. CRDTs make the eventual reconciliation safe since concurrent optimistic changes merge without conflict. The cost is complexity around the failure path: handle rollback, surface conflicts the merge cannot silently resolve, and design UI that tolerates a change being undone.
A monorepo holds many packages or apps in one repository. The benefits: shared code without publishing, atomic cross-package changes, a single source of truth for versions and tooling. The challenge that orchestration tools exist to solve is build performance at scale — naively, every change rebuilds and retests everything.
The orchestration techniques (Nx, Turborepo, Bazel):
The mental model: the tool turns "rebuild the world" into "rebuild only the affected slice, and reuse cached results for the rest."
An AST (Abstract Syntax Tree) is the tree representation of source code after parsing. AST transformation is the parse → transform → generate cycle: parse code into a tree, manipulate the tree, regenerate code from it. This is how most of the modern toolchain works:
All of this is "parse to a tree, walk and rewrite the tree, print it back." Knowing that demystifies the toolchain.
Sometimes off-the-shelf bundler config is not enough and you compose your own pipeline. This means writing plugins against a bundler's API (Rollup and Vite share a plugin interface, esbuild has its own), custom loaders or transforms, and code generation steps. Reasons to do it: a bespoke file type, generating code from a schema (types from GraphQL, routes from a file tree), or integrating a non-standard tool. The discipline is to lean on the bundler's plugin hooks (resolve, load, transform) rather than bolting on separate scripts, so the work stays inside the dependency graph and benefits from caching and HMR.
Server-Driven UI (SDUI) moves the description of the interface from the client to the server. Instead of the client owning the layout and the server sending only data, the server sends a structured description of the UI — layout, which components, their props, and the data — and the client renders it from a registry of components it already ships.
The pieces:
The honest tradeoffs: the client can only render components it already has, so genuinely new UI still needs a client release. You take on schema versioning and backward compatibility. There is extra payload and a render-time mapping cost. It suits content-driven, frequently-changing surfaces (feeds, landing screens, promos) far better than deeply interactive bespoke UI.
Microfrontends extend the microservices idea to the frontend: decompose a large app into independently developed, owned, and deployed pieces that compose into one experience. The motivation is organizational scaling — letting many teams ship without coordinating a single monolithic release.
The dimensions:
The honest critique: microfrontends carry real costs — operational complexity, duplicated dependencies bloating the bundle, shared-dependency version conflicts, and consistency drift. They are right for large organizations with many independent teams, and usually overkill for a small team where they add infrastructure pain without the organizational payoff. The architecture solves a people-scaling problem.
Both WebGL and WebGPU give web pages access to the GPU. The programmable core is the shader: a small program that runs on the GPU, executed massively in parallel across thousands of cores.
Shaders are written in a dedicated language: GLSL for WebGL, WGSL for WebGPU. A shader describes what happens to one vertex or pixel, and the GPU runs that same program over all of them in parallel. That parallelism is the entire point.
Hardware acceleration offloads work from the CPU to the GPU, which is purpose-built for the highly parallel arithmetic of graphics. The CPU sets up data and issues draw calls, and the GPU executes shaders across its cores. Rasterization converts geometry (triangles) into pixels (fragments) for the fragment shader to color. Doing this on dedicated GPU hardware is what makes real-time 3D and large 2D scenes feasible at 60fps.
WebGPU is the modern successor to WebGL, built on current native GPU APIs (Vulkan, Metal, Direct3D 12) rather than the aging OpenGL ES that WebGL wraps. What it brings: lower CPU overhead, explicit lower-level control over GPU resources, and crucially compute shaders — general-purpose GPU computation not tied to drawing, opening the door to in-browser machine learning, physics, and data processing on the GPU. It uses WGSL for shaders.
In practice almost nobody writes raw WebGL or WebGPU. You use Three.js or Babylon.js for 3D, PixiJS for high-performance 2D. Knowing the layer beneath those libraries is the expert-level understanding being tested.
WebAssembly is a binary instruction format that serves as a portable compilation target. You write in C, C++, Rust, Go, or others, compile to WASM, and run it in the browser inside a secure sandbox at near-native speed.
Three angles:
WASM complements JavaScript — JS orchestrates the app and owns the DOM, WASM handles the compute-intensive core. Tooling: Emscripten for C/C++, wasm-pack and wasm-bindgen for Rust, AssemblyScript for a TypeScript-like experience.
Modern browsers are multi-process. Chrome's model: a browser process (UI, coordination), multiple renderer processes (one per site, roughly), a GPU process, and a network process. The driving reason beyond stability is site isolation: putting each site in its own process so that even a Spectre-class memory-reading attack cannot reach another site's data. The security boundary is why the architecture looks the way it does.
The renderer is where a page becomes pixels, running several threads:
transform/opacity animations without the main thread — the deep reason those operations stay smooth even when the main thread is busy.The throughline: changing geometry re-runs layout and everything after it (expensive). Changing only paint properties skips layout. Changing only transform/opacity is handled by the compositor alone, skipping layout and paint entirely.
V8 compiles JavaScript rather than purely interpreting it. The flow: source is parsed and compiled to bytecode run by the Ignition interpreter. Hot code (run many times) is handed to optimizing compilers (Maglev and TurboFan) that produce fast machine code, with deoptimization falling back to bytecode if an assumption breaks.
Two mechanisms for writing fast JS: hidden classes (V8 builds internal shapes for objects — consistent property order and types let it optimize property access) and inline caches (caching where a property lives after the first lookup). Garbage collection is generational and mostly concurrent/incremental (the Orinoco collector), designed to avoid long stop-the-world pauses that cause jank.
Per frame, the browser runs a task, drains all microtasks, then runs rendering steps — including requestAnimationFrame callbacks (run right before layout and paint, the correct place to drive animations), then style, layout, and paint. requestIdleCallback schedules low-priority work for leftover time in a frame.
JavaScript, rendering, and the event loop all share the main thread. Rendering only happens between tasks after microtasks drain. This is the unifying model behind nearly every performance topic in this roadmap.
Four tiers complete:
Three threads run through the whole thing. The rendering pipeline (DOM and CSSOM to render tree to layout to paint to composite) explains performance from Tier 2's reflow discussion through Tier 4's engine internals. The single-threaded event loop with its task/microtask/render ordering explains async behavior, timers, and responsiveness everywhere. HTTP caching with content-hashed immutable assets explains both Tier 1 networking and Tier 2 deployment. Trace those three threads across tiers and you understand the platform, not just a list of features.
Goal: Understand the expert tier — local-first systems, frontend tooling, server-driven UI, microfrontends, WebGL/WebGPU, WASM, and browser internals — that defines expert-level frontend engineering.
Continue learning with these related challenges
The mental models and edge cases that separate someone who has used HTML, CSS, JS, forms, responsive design, and HTTP from someone who actually understands them. Part 1 of the Frontend Roadmap series.
Accessibility, state management, component design, media optimization, rendering strategies, fonts, testing, and deployment — the intermediate tier where most mid-level interviews actually live. Part 2 of the Frontend Roadmap series.
Build systems, security, offline-first patterns, internationalization, maintainable CSS, performance internals, and design systems — the advanced tier where senior-level depth is tested. Part 3 of the Frontend Roadmap series.
The mental models and edge cases that separate someone who has used HTML, CSS, JS, forms, responsive design, and HTTP from someone who actually understands them. Part 1 of the Frontend Roadmap series.
Accessibility, state management, component design, media optimization, rendering strategies, fonts, testing, and deployment — the intermediate tier where most mid-level interviews actually live. Part 2 of the Frontend Roadmap series.
Build systems, security, offline-first patterns, internationalization, maintainable CSS, performance internals, and design systems — the advanced tier where senior-level depth is tested. Part 3 of the Frontend Roadmap series.