Skip to content

damiansire/web-worker-patterns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

257 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Mastering Web Workers

Field Value
Status Stable
Last updated Sunday, 22 June 2026

Angular TypeScript License

🌐 This README is also available in other languages: EspaΓ±ol | PortuguΓͺs

Interactive educational platform about Web Workers built with Angular 22. It ships 16 progressive examples with live demos and real thread visualization, multi-language support (ES/EN/PT), and 5 swappable visual themes β€” the same neutral domain rendered five different ways.

β–Ά Live demo: damiansire.github.io/web-worker-patterns

Quick Start

On any system (Windows, macOS, Linux):

git clone https://github.com/damiansire/web-worker-patterns.git
cd web-worker-patterns
npm run dev

npm run dev checks Node.js (β‰₯18) and npm (β‰₯9), installs dependencies if needed, and starts the server at http://localhost:4200.

Alternatives:

  • Just start (if you already ran npm install): npm start
  • Windows: double-click scripts/start/start.bat, or in a terminal: npm run dev
  • macOS/Linux: in a terminal: ./scripts/start/start.sh or npm run dev

Open http://localhost:4200 in your browser.

Included Examples

The 16 examples are organized into 5 categories by concept. The grouping below mirrors src/app/core/domain/examples/examples.registry.ts β€” the single source of truth.

Understanding

# Example Description
01 Counter with setInterval How setInterval and the event loop work β€” the baseline to grasp before workers.
02 The main thread & event loop One thread runs JS, layout, paint and input; a 50 ms task freezes everything.
16 Compositor vs main The compositor thread keeps transform/opacity animations smooth even while the main thread is frozen.

Communication

# Example Description
03 Basic communication The "Hello World" of workers β€” postMessage in both directions.
08 SharedWorker One worker instance shared across tabs/panels, all seeing the same state.

Optimization

# Example Description
04 Offload heavy work Count primes on a worker so the UI stays responsive β€” feel the difference side by side.
07 Transferable objects Pass an ArrayBuffer zero-copy; the sender's buffer is left detached.
10 Worker pool A fixed pool of N workers drains a task queue (4 workers, 24 tasks).
14 OffscreenCanvas A worker owns the canvas and animates it β€” smooth even when the main thread blocks.
15 The cost of cloning Measure the real round-trip of structured clone as data size and complexity grow.

Management

# Example Description
05 Error handling A worker error doesn't crash the page; the main thread catches it.
06 Lifecycle & termination Create, run and terminate() β€” the in-flight step is lost and the worker can't be reused.
09 Limits of parallelism navigator.hardwareConcurrency caps real parallelism; beyond it, workers share cores.

Advanced

# Example Description
11 Backpressure Flow control with credits and acks so the worker's queue doesn't grow without bound.
12 SharedArrayBuffer Main and worker share the same memory; Atomics write/read with no postMessage.
13 Graceful degradation Detect typeof Worker and fall back to the main thread when it's missing.

Visual Themes

The same domain is skinned by 5 independent themes, switchable live from the UI:

Brutalist Β· Full Brutalist Β· Dev Tool Β· Editorial Β· Narrative

Each theme provides its own shell, home, example layout, UI primitives and a custom thread visualizer β€” without the domain ever knowing a theme exists.

Project Architecture

The golden rule: the domain is written once; the presentation is written five times. core/ is theme-neutral and never imports from themes/. The full rationale lives in ARQUITECTURA-multi-theme.md.

src/app/
β”œβ”€β”€ core/                       # Neutral domain β€” knows nothing about themes
β”‚   β”œβ”€β”€ domain/
β”‚   β”‚   β”œβ”€β”€ workers/            # Real Web Workers + pure *.logic.ts (unit-tested)
β”‚   β”‚   └── examples/           # examples.registry.ts (source of truth) + code snippets
β”‚   β”œβ”€β”€ services/               # Per-example demo services (signals-based)
β”‚   β”œβ”€β”€ i18n/                   # Transloco loader
β”‚   β”œβ”€β”€ styles/                 # Shared SCSS (_buttons, _containers, _example-layout)
β”‚   └── utils/                  # Helpers (code-snippet.helper)
β”œβ”€β”€ theming/                    # Theme registry, service, guard, token contract
β”œβ”€β”€ ui-contracts/               # Interfaces every theme primitive must satisfy
β”œβ”€β”€ ui-primitives/              # Theme-agnostic primitives (charts, language switcher)
β”œβ”€β”€ themes/                     # Presentation β€” one folder per theme
β”‚   β”œβ”€β”€ brutalist/  full-brutalist/  dev-tool/  editorial/  narrative/
β”‚   β”‚   β”œβ”€β”€ shell/  home/  example-layout/  primitives/  styles/
β”œβ”€β”€ app.routes.ts              # Routes generated from the examples registry
└── app.ts                     # Root component

public/i18n/                    # en.json Β· es.json Β· pt.json (UI + per-example content)

Adding a New Example

A new example is one neutral domain definition rendered by all 5 themes. The full pipeline is codified in the /migrate-example command (.claude/commands/migrate-example.md). In short:

  1. Add the worker in core/domain/workers/ (+ a pure *.logic.ts with a unit test) and its snippets under core/domain/examples/snippets/.
  2. Register it in core/domain/examples/examples.registry.ts (id, order, category, demo, workerFactory).
  3. Add the educational content (title, summary, takeaways) to public/i18n/{en,es,pt}.json.
  4. Wire the demo's visualization into the @case of each theme's example layout.

Routes, navigation and the home page update automatically from the registry.

Tech Stack

  • Angular 22 β€” Standalone components, Signals, zoneless change detection (opt-in via provideZonelessChangeDetection()), esbuild-based build
  • TypeScript 6.0.3
  • SCSS β€” Semantic design tokens (--surface, --ink, --accent, --thread-*) per theme
  • @jsverse/transloco β€” Runtime i18n (ES/EN/PT)
  • highlight.js β€” Syntax highlighting for code blocks
  • Vitest β€” Unit tests (100+ tests across the pure domain logic, the services and the themes)
  • dependency-cruiser β€” Enforces the core/ ⇏ themes/ boundary
  • Web Workers API β€” Dedicated Workers, SharedWorker, Transferable Objects, SharedArrayBuffer + Atomics, OffscreenCanvas

This project uses Angular's built-in worker support (@angular/build / esbuild). Other setups use worker-plugin (webpack), rollup-plugin-off-main-thread, or Parcel's native worker support.

Angular Version

This project targets Angular 22 with @angular/build and a dedicated webWorkerTsConfig for worker bundles.

If you are upgrading from an older major version, use the Angular update tool and follow the official migration guidance:

ng update @angular/core @angular/cli

Then:

  • Zoneless (opt-in): Angular is not zoneless by default; this app enables it with provideZonelessChangeDetection() in app.config.ts (which is why it ships no zone.js in polyfills). It relies on Signals and computed() for change detection.
  • Tests: tsconfig.spec.json excludes **/*.worker.ts, so worker files are not compiled with the DOM Window type.
  • Build: @angular/build is the standard builder and bundles the app with esbuild.

Available Scripts

npm run dev            # Checks Node/npm, installs deps if needed and starts the server (all platforms)
npm start              # Dev server at localhost:4200 (requires a prior npm install)
npm run build          # Production build
npm test               # Gate: ESLint + ng build + unit tests (Vitest)
npm run lint           # ESLint: no-console, mandatory OnPush, keyboard a11y
npm run format         # Format the code with Prettier
npm run format:check   # Check formatting without writing (CI gate)
npm run lint:boundaries# Enforce the golden rule (core/ ⇏ themes/)

Quality gates (lint, build, format, tests, boundaries) run on every push/PR via CI and as a local git pre-commit hook β€” independent of your editor. ESLint enforces the invariants the repo preaches: no-console in the lib, ChangeDetectionStrategy.OnPush on every component (the app is zoneless), and keyboard a11y in templates. See AGENTS.md and docs/AI-PROCESS.md.

Multi-language Support

The application supports English, Spanish, and Portuguese via Transloco. Translations live in:

  • public/i18n/en.json Β· public/i18n/es.json Β· public/i18n/pt.json β€” UI text and the educational content for every example

Switch languages from the selector in each theme's shell.

Documentation

Further reading

  • Use web workers to run JavaScript off the browser's main thread (web.dev) β€” Why off-main-thread architecture helps Core Web Vitals (INP, LCP) and reduces main-thread contention.
  • Comlink β€” Use workers without writing postMessage by hand; expose an API that returns promises. This repo uses the native API to teach the fundamentals.
  • PROXX β€” Case study: Minesweeper clone with game logic in a worker and rendering on the main thread; see the web.dev article for the tradeoffs (reducing risk and improving UX rather than raw speed).

License

MIT

About

An interactive platform demonstrating advanced Web Worker patterns and architectural strategies.

Topics

Resources

License

Stars

175 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors