Part 8 · 2 chapters · ~12 min

Build

From source to a release: transpiling and bundling, tree shaking and minification, splitting and hashing, monorepos and packages, CI gates and previews, flags and trains.

18

Compiling and bundling

From source files to optimised, hashed chunks.

Bundler

entrymain.tsxmodule g…resolve imp…transformTS, JSX, CSSchunkshashed files

A tool that follows imports from entry points, transforms each module and emits a small number of optimised files for the browser.

in practiceVite (Rollup or Rolldown), webpack, esbuild, Rspack, Turbopack; the dist folder.

deep dive: Architecture P1

Transpiler

TSXtypes + JSXSWC / esbuildstrip, transformJSfor the target

A compiler from one JS dialect to another: TypeScript and JSX to plain JS, or modern syntax down to older targets.

in practiceSWC, esbuild, Babel; the browserslist target that decides what is down-levelled.

deep dive: Architecture P1

Tree shaking

utils.jsformat() ✓ us…parse() ✗debounce() ✗unused exports dropped

Removing exports that nothing imports, based on the static structure of ES modules.

in practiceImporting one lodash-es function without the rest; sideEffects: false in package.json enabling it.

Side effects (package)

"sideEffects": falsesafe to drop unused modules"sideEffects": ["*.css"]keep CSS imports(absent)assume everything has effec…

Code that runs on import (polyfills, CSS imports, global registration); bundlers must keep it, so it blocks tree shaking unless declared absent.

in practicesideEffects: ["*.css"] in package.json; a library that ships everything because of one top-level call.

deep dive: Architecture P1

Code splitting

entry (60 KB)vendor (90 KB)/settings/reports/admin/checkoutroutes load on navigation

Breaking the bundle into chunks loaded on demand, usually at dynamic import() boundaries such as routes.

in practiceReact.lazy(() => import("./Settings")); a smaller entry chunk and faster first load.

deep dive: Architecture P1

Chunk and content hash

app.3f9a1c.jsimmutable, 1 yearvendor.81bd02.jsimmutable, 1 yearindex.htmlno-cache (points at hashes)

Output files are named by a hash of their contents, so they can be cached forever and a change produces a new URL.

in practiceapp.3f9a1c.js with Cache-Control immutable; index.html not hashed and revalidated.

deep dive: Architecture P1

Minification

sourcefunction total(items) { return items.reduce( (s, i) => s + i.p, 0);}minifiedfunction t(e){return e.reduce((t,e)=>t+e.p,0)}

Shrinking JS and CSS without changing behaviour: removing whitespace, shortening names, folding constants, dropping dead branches.

in practiceTerser, esbuild and SWC minifiers; why production stack traces need source maps.

deep dive: Architecture P1

Source map

a.js:1:4093minifiedsource mapmappingsCart.tsx:42original

A file mapping minified output back to original sources, lines and names, so debuggers and error tools show your code.

in practiceReadable stack traces in Sentry; upload maps privately, do not serve them publicly.

Polyfill

if (!('structuredClone' in globalThis)) { await import('./polyfills/structured-clone');}

Code that implements a missing platform API in older browsers, loaded only when needed.

in practicecore-js; a polyfill for structuredClone; differential serving to skip them on modern browsers.

deep dive: Architecture P1

Module federation

host appremote Adeployed al…remote Bdeployed al…sharedreact, ds

Loading separately built and deployed bundles into one app at runtime, sharing dependencies between them.

in practiceMicro-frontends at large companies; version skew of shared React a common failure.

HMR

editordev serverbrowsersave Button.tsxupdate moduleswap, keep state

Hot module replacement: swapping a changed module into the running app without a full reload, preserving state where possible.

in practiceVite and React Fast Refresh in development; full reloads when a module cannot be hot-swapped.

deep dive: Architecture P1

Bundle analyser

moment (290 …momentchart libappmomentmomentchart libreactthe treemap names the import to replace

A visualisation of what is in each chunk and how big, to find heavy or duplicated dependencies.

in practicerollup-plugin-visualizer, webpack-bundle-analyzer, source-map-explorer treemaps.

deep dive: Architecture P1
THE BUILD LAYER, IN ORDER
from source files to a deployed, versioned, flagged release
swipe the figure sideways, or tap expand for full screen
1/6
compile
Compile: transpilers turn TS and JSX into JS for the target; bundlers walk the graph; HMR swaps modules in development; polyfills fill gaps.
19

Repos, CI and release

From a repository of packages to a gated, previewed, flagged release.

Monorepo

repoapps/webadminpackages/uiapi-cli…one change can touch all of them atomically

Many packages and apps in one repository with shared tooling, atomic cross-package changes and one version of the truth.

in practicepnpm workspaces, Nx, Turborepo, Bazel; Google, Meta and Microsoft's main repositories.

Task graph and caching

web:buildui:build (cac…api-client:bu…only changed inputs rebuild

Monorepo tools model builds and tests as a dependency graph and skip tasks whose inputs are unchanged, locally or from a remote cache.

in practiceTurborepo and Nx "cache hit" output; CI times that stay flat as the repo grows.

Affected (only changed)

ui (changed)web (affected)admin (affected)docsapimobile

Running builds and tests only for projects affected by a change, computed from the dependency graph.

in practicenx affected, turbo --filter=...[origin/main]; keeping CI fast in big repos.

Semantic versioning

2.0.0breaking change1.5.0new feature, compatible1.4.1bug fix^1.4.0accepts 1.x ≥ 1.4.0

MAJOR.MINOR.PATCH: breaking changes bump major, features minor, fixes patch; ranges like ^1.4.0 accept compatible updates.

in practiceDesign systems communicating breaking changes; caret ranges pulling surprise minor versions.

deep dive: Design P3

Lockfile

package.json"react": "^19.0.0"lockfile[email protected] sha512-…

A file recording the exact resolved version of every dependency, so every install produces the same tree.

in practicepackage-lock.json, pnpm-lock.yaml; npm ci and frozen lockfiles in CI; supply chain reviews.

Peer dependency

dependencylibrary brings its owntwo Reactshooks breakpeerDependencyhost provides itone Reactshared

A dependency a library expects the host app to provide (React for a component library), so only one copy exists.

in practiceDuplicate React errors ("invalid hook call") when a library bundles its own.

deep dive: Design P3

Dual package (ESM/CJS)

"exports": { ".": { "import": "./dist/index.mjs", "require": "./dist/index.cjs", "types": "./dist/index.d.ts" } }

A package shipping both ES modules and CommonJS via the exports map, so it works in both module systems.

in practiceThe "exports" field with import and require conditions; the dual-package hazard of two instances.

deep dive: TypeScript P8

Environment variables (build-time)

VITE_API=….envbuildinlinebundlepublic string

Values substituted into the bundle at build time (import.meta.env.VITE_*, process.env.NEXT_PUBLIC_*); public by definition.

in practiceAPI base URLs per environment; never secrets, because they end up in the shipped JS.

deep dive: Disciplines P6

CI pipeline

insta…typec…testbuild…previ…

The automated checks on every change: install, typecheck, lint, test, build, size and performance gates, preview deploy.

in practiceGitHub Actions workflows; required checks blocking merge.

Preview deployment

PR #812buildpr-812.previ…review, e2e, Lig…

A deployed copy of each pull request at its own URL, for review, end-to-end tests and lab performance runs.

in practiceVercel and Netlify previews; Lighthouse CI against the preview.

deep dive: Architecture P2

Feature flag

new-checkout10% of NG userskill-switch: chatoffab: price-layoutA 50 / B 50

A runtime switch that turns code paths on or off per user, cohort or percentage without a deploy.

in practiceDark launches, kill switches, gradual rollouts, A/B tests; stale flags as debt.

Release train

cutdogfo…1%10%100%halts on a metric breach at any ring

Shipping on a fixed schedule with whatever is ready, behind flags, through staged rings, rather than releasing per feature.

in practiceWeekly web trains and mobile store releases; rings from employees to 1% to 100%.