web-redesign-and-library-vision.md
April 12, 2026 · View on GitHub
We rebuilt the Angular Helpers website from scratch. Not because the old one was broken, but because it had grown in ways that made it hard to change — inconsistent folder structures, ad-hoc CSS that only the author understood, and a narrative that didn't actually explain why you'd want to use these libraries.
This article explains what we changed, why, and the principles behind it.
The problem we were solving
Every Angular application we've worked on has the same pattern: early in the project someone writes a GeolocationService. Then someone else writes a ClipboardService. Then a WebSocketService. Each one is slightly different, each one has slightly different lifecycle handling, and none of them have been tested in a real browser.
The browser platform has gotten incredibly capable. Web APIs that used to require native apps — camera access, Bluetooth, NFC, payments, file system access — are now available from JavaScript. But nobody ships a well-typed, lifecycle-aware Angular service for them. You write your own, every time.
That's the gap @angular-helpers fills. We solved it once, properly, and made it tree-shakable so you only pay for what you use.
What each package stands for
browser-web-apis — Lightweight. Standard.
37 typed Angular services. One provider function. Every service respects permissions, handles secure-context requirements, cleans up with DestroyRef, and exposes its state as Angular signals. If a browser API exists and is worth wrapping, it's in here.
The promise is lightweight and standard: we follow the Web API spec closely, add no unnecessary abstraction, and keep the bundle impact minimal.
security — Robust. Safe.
ReDoS is a real vulnerability. A catastrophically backtracking regex can lock your main thread for seconds. @angular-helpers/security runs regex evaluation in a Web Worker with a configurable timeout — the main thread is never blocked.
Beyond regex, the package includes WebCrypto utilities (AES-GCM, HMAC), encrypted localStorage/sessionStorage, XSS-safe input sanitization, and entropy-based password strength scoring.
worker-http — Performance. Off-main-thread.
HTTP requests block the main thread. Not a lot, but measurably. @angular-helpers/worker-http moves your HTTP calls into a Web Worker with a typed RPC bridge. You call the same familiar API, the work happens off-thread, and your UI stays responsive.
It ships with 7 built-in interceptors: retry, cache, HMAC signing, rate limiting, and more.
Technical decisions in this rebuild
Tailwind v4 + DaisyUI v5
We dropped all ad-hoc CSS and moved to Tailwind v4 (CSS-first, no config file) with DaisyUI v5 for component primitives. The existing dark color palette was mapped to a custom DaisyUI theme named angular-helpers, so the visual identity is preserved but now backed by a proper design system.
Mobile-first throughout. The old site had several desktop-first overrides that made narrow viewports feel like an afterthought.
Canonical section structure
Every top-level section of the app (home/, demo/, docs/, blog/) now follows the same internal convention:
section/
├── section.component.ts ← entry page
├── section.routes.ts ← self-contained routing
├── ui/ ← presentational components
├── feature/ ← smart components
├── config/ ← constants & data
├── models/ ← TypeScript interfaces
├── store/ ← signals (if needed)
└── services/ ← section-scoped DI
The goal is that each section is a black box. You import the entry component, it adds its own routing. No leaking internals.
Templates + Resolvers — components are receivers, not fetchers
The biggest structural principle in this rebuild is that route components don't fetch their own data. Instead:
- The route defines a resolver that fetches/constructs the data
- The component receives it via
ActivatedRoute.dataand renders it - The same component can render entirely different content depending on what the resolver provides
This is already in place for the docs section — UnifiedOverviewComponent and UnifiedServiceDetailComponent are pure templates. The resolver decides what config they receive. Three different npm packages share one overview template and one service-detail template.
The blog section follows the same pattern: articles are .md files stored in public/content/blog/. The BlogPostResolver fetches the file, parses the frontmatter and renders the markdown to HTML, then passes a BlogPostData object to the route. BlogPostComponent receives it and renders the template.
shared/ vs core/ separation
shared/ is now strictly a deduplication boundary: components used in two or more sections live here. Single-section code lives inside the section.
core/ is new: global systems that affect the entire app — i18n translations, navigation data, app-wide constants. Not UI components.
Blog as Markdown — easy to read in the repo
Blog articles live as plain .md files. Anyone who visits the GitHub repository can read them directly without rendering. The README.md links to articles that are relevant to the library's evolution.
Each article has YAML frontmatter (title, date, tags, excerpt) that drives both the list page and the article header. Adding a new article means:
- Create
public/content/blog/your-slug.mdwith frontmatter - Add an entry to
src/app/blog/config/posts.data.ts - Done — the resolver and template handle the rest
i18n from day one
The site is English-first, but all UI copy is sourced from core/i18n/en.ts. Adding a second language means adding a new file and wiring it into the signal-based I18nService. No template strings need to change.
What comes next
The docs section will get the same Tailwind treatment. Then we'll add bundle size tracking — we want to make the "lightweight" claim verifiable with real numbers.
And we'll keep shipping browser API services. If there's a Web API you're wrapping by hand in every Angular project, open an issue.