Files
2026-05-27 23:29:53 +01:00

3.3 KiB

Tasks: enterprise-react-font-decompress

Change ID: enterprise-react-font-decompress Package: @suaveplan/react-font-decompress Target path: react/media/react-font-decompress Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/font-decompress


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory tree. Write package.json at 0.1.0, tsconfig.json, vitest.config.ts, scripts.
  • Dependencies: @suaveplan/error workspace:^, @suaveplan/font-decompress workspace:^, zod catalog:forms, tslib catalog:build.

2. Error codes

  • Define FontError; codes: FONT_LOAD_FAILED, FONT_DECODE_FAILED.

3. BinaryFontLoader

  • Module-level cache: Map<url, Promise<TypefaceFont>>.
  • BinaryFontLoader.load(url: string, fetchFn?: typeof fetch): Promise<TypefaceFont>:
    • Returns cached promise if URL already in map.
    • Fetches ArrayBuffer, delegates decode to @suaveplan/font-decompress.
    • Throws FontError(FONT_LOAD_FAILED) on fetch error; FontError(FONT_DECODE_FAILED) on decode error.
    • Removes from cache on rejection so retry is possible.
  • Write binary-font-loader.test.ts (≤500 lines): load, cache dedup (same URL returns same promise), fetch error, decode error, retry after error. DI injected fetchFn. { timeout: 10000 }.
  • Write binary-font-loader.md.

4. createBrowserLoader

  • Returns an inline-script string (self-contained, no imports) that can be injected as <script> for zero-dep browser font loading.
  • Write browser-loader.test.ts: returned string is valid JS (eval in sandbox), loads a font given an ArrayBuffer. { timeout: 5000 }.
  • Write browser-loader.md.

5. Hooks

useFont

  • useFont(url: string, fetchFn?): calls BinaryFontLoader.load; returns { font, loading, error }.
  • Write use-font.test.ts (≤500 lines): loading state, success state, error state, cache reuse on re-render. { timeout: 10000 }.
  • Write use-font.stories.tsx: playground (URL input → show font name).
  • Write use-font.md.

useFonts

  • useFonts(urls: string[], fetchFn?): loads all in parallel; returns { fonts, loading, error }.
  • Write use-fonts.test.ts: all loaded, partial error, empty array. { timeout: 10000 }.
  • Write use-fonts.stories.tsx: playground (multiple URLs).
  • Write use-fonts.md.

6. Verify and publish

  • bunx turbo lint typecheck test --filter=@suaveplan/react-font-decompress — green.
  • bunx turbo test:coverage --filter=@suaveplan/react-font-decompress — 100%.
  • bun scripts/publish.ts --package @suaveplan/react-font-decompress.
  • Archive change folder.