Research: Replace / drop npm libs with built-in browser APIs (2026) to slim spikersoft-angular #866

Open
opened 2026-07-27 02:46:14 +00:00 by spikerj · 0 comments
Owner

Summary

Research spike (curiosity / cleanup): inventory what spikersoft-angular still ships that can be replaced by built-in browser APIs in 2026, or dropped as unused, to slim dependencies and feature chunks.

Browser target already helps a lot (browserslist):

chrome >= 120
edge >= 120
firefox >= 120
safari >= 17

The app is already zoneless (provideZonelessChangeDetection(), polyfills: []). Several “compat” packages look overdue for pruning.

Already native in this codebase: crypto.randomUUID() (several call sites), navigator.clipboard, URL.createObjectURL + <a download>, AbortController, ResizeObserver/IntersectionObserver at runtime. No lodash/date-fns/moment/file-saver. No package.json "browser" shims.

Not in scope: replacing product engines (Monaco, Three, Leaflet, Keycloak, SignalR, PDF.js viewer, Tesseract, DuckDB, Blockly, Rete, Pyodide, Clang, v86, etc.) unless there is a genuine native alternative.

Related research: OPFS / offline pin+outbox — #865.


Highest-confidence drops

Package / code Size (approx) Used where Native / reality Verdict
process ^0.11.10 ~1.5 KB gz Import in polyfills.ts commented out; polyfills: [] Node polyfill — unused DROP direct dep
temporal-polyfill ^1.0.1 ~32.5 KB gz Zero app imports Temporal not Baseline yet (Safari still missing); package unused today DROP direct dep (FullCalendar may still bring its own transitively)
zone.js 0.16.2 ~13 KB gz if loaded Not imported; zoneless boot Leftover DROP from our deps; confirm Storybook/tests don’t still pull it
asn1js ^3.0.10 ~16 KB gz No imports — voxel uses custom ASN1.ts (+ asset) No ASN.1 platform API DROP npm package; keep custom parser
bigint-mod-arith ^3.3.1 ~1 KB gz npm npm unused — code imports vendored util/bigint-mod-arith.ts from CryptManager.ts No BigInt.modPow DROP npm package; keep vendored modPow
uuid ^14.0.1 ~0.4 KB gz v4 Sole import: menu-bar.component.tsguid = uuidv4()appears unused in template crypto.randomUUID() — Baseline DROP — swap or delete guid
js-sha1 ^0.7.0 ~2.6 KB gz (+ vendored asset) Voxel Authentication.createServerHash crypto.subtle.digest("SHA-1", …) — Baseline for digest DROP — keep Minecraft signed-hex post-processing; hash step becomes async
@spikersoft/shared-utils-crc32 tiny No production consumers (alias + self-tests only) No CRC-32 browser API DROP unused leaf lib (or wire it later)

Also noted as likely unused direct deps in an earlier pass (confirm dynamic import / assets before delete): mermaid, ngx-socket-io, avif.js, three-addons. Real AVIF path is @jsquash/avif.


Strong “maybe replace with built-ins”

Package / pattern Why it exists Native angle Caveat
fflate ^0.8.3 (~12–22 KB gz) x86 playground sync gzip for localStorage + share-URL parity with upstream x64.halb.it CompressionStream("gzip") / DecompressionStream — Baseline (Safari 16.4+) Async rewrite; gzip header mtime/filename must stay byte-compatible with share URLs
pako ^3.0.1 (~14 KB gz; fat ES5 asset also present) Voxel NetworkManager sync zlib inflate/deflate on hot packet path CompressionStream("deflate") / decompress — Baseline Sync → async forces packet pipeline redesign; confirm zlib vs deflate-raw; prefer dropping fat asset if npm import is real
Custom AES-CFB (wasm-voxel/.../aes.ts) Minecraft login encryption SubtleCrypto has CBC/GCM/CTR — not CFB KEEP
ngx-mask ^22.1.0 (~44 KB gz) Global provideEnvironmentNgxMask() in main.ts; only Marks phone fields No input-mask API MAYBE custom formatter, or at least move provider into Marks lazy route
JSON.parse(JSON.stringify(...)) clones e.g. rete/quicktype structuredClone() — Baseline Easy cleanup

Keep — no real browser replacement

Area Packages / code Why keep
Git playground isomorphic-git, lightning-fs, wasm-git OPFS = storage, not Git. Note: wasm-git has OPFS builds (lg2_opfs*) — possible evolution to drop lightning-fs IndexedDB layer later (#865-adjacent)
Archives jszip Compression Streams ≠ ZIP container
Game protocol @msgpack/msgpack Must match .NET server wire format
QR ng-qrcode BarcodeDetector is decode-only
EPUB XSS dompurify (#409) HTML Sanitizer / setHTML not Baseline — Safari still missing
Streaming hls.js + ovenplayer OvenPlayer expects hls.js global
Tours / engines intro.js, Monaco, Blockly, Rete, Three, Leaflet, Keycloak, SignalR, PDF viewer, Tesseract, DuckDB, etc. Product features
tslib Angular/TS emit helpers Ecosystem expectation
Custom voxel crypto ASN1, AES-CFB, Minecraft UUID Protocol-specific; only js-sha1 is the easy native swap
pdfjs-dist Likely assets for extended PDF viewer Verify before deleting

Suggested execution order

  1. Dead deps: process, temporal-polyfill (direct), asn1js, bigint-mod-arith (npm), zone.js (our dep), unused crc32 lib; plus audit mermaid / ngx-socket-io / avif.js / three-addons
  2. One-liners: uuid → delete/crypto.randomUUID(); js-sha1crypto.subtle.digest("SHA-1") (+ remove vendored sha1.min.js if unused)
  3. Optional: fflate → CompressionStream (share-URL byte parity); scope ngx-mask out of main.ts
  4. Harder: pako on Minecraft packets
  5. Wait: dompurify until Safari ships Sanitizer API

Success metrics

  • Direct dependency count down; no production import of removed packages
  • Voxel join/auth works without js-sha1
  • Menu-bar behavior unchanged (or dead guid removed)
  • EPUB XSS tests (#409) still green if DOMPurify untouched
  • Optional bundle delta on affected lazy chunks

Prime examples

js-sha1 → Web Crypto

// today
const bytes = sha1.create().update(...).update(...).update(...).digest();

// native
const digest = new Uint8Array(await crypto.subtle.digest("SHA-1", concatenatedBytes));
// keep existing Minecraft sign/hex post-processing

uuidcrypto.randomUUID() (or delete unused guid)

Single remaining npm import in menu-bar.component.ts; everywhere else already migrated.


Ask

  1. Approve a dead-deps + uuid/js-sha1 cleanup PR (low risk).
  2. Optionally schedule fflateCompressionStream spike (+ ngx-mask main-bundle scoping).
  3. Do not chase DOMPurify / AES-CFB / git / zip / msgpack / heavy engines for “native replace” — wrong ROI or no API.
## Summary Research spike (curiosity / cleanup): inventory what `spikersoft-angular` still ships that can be replaced by **built-in browser APIs in 2026**, or dropped as unused, to slim dependencies and feature chunks. **Browser target already helps a lot** (`browserslist`): ```text chrome >= 120 edge >= 120 firefox >= 120 safari >= 17 ``` The app is already **zoneless** (`provideZonelessChangeDetection()`, `polyfills: []`). Several “compat” packages look overdue for pruning. **Already native in this codebase:** `crypto.randomUUID()` (several call sites), `navigator.clipboard`, `URL.createObjectURL` + `<a download>`, `AbortController`, ResizeObserver/IntersectionObserver at runtime. No lodash/date-fns/moment/file-saver. No `package.json` `"browser"` shims. **Not in scope:** replacing product engines (Monaco, Three, Leaflet, Keycloak, SignalR, PDF.js viewer, Tesseract, DuckDB, Blockly, Rete, Pyodide, Clang, v86, etc.) unless there is a genuine native alternative. Related research: OPFS / offline pin+outbox — #865. --- ## Highest-confidence drops | Package / code | Size (approx) | Used where | Native / reality | Verdict | |---|---|---|---|---| | **`process`** ^0.11.10 | ~1.5 KB gz | Import in `polyfills.ts` **commented out**; `polyfills: []` | Node polyfill — unused | **DROP** direct dep | | **`temporal-polyfill`** ^1.0.1 | ~32.5 KB gz | **Zero app imports** | `Temporal` not Baseline yet (Safari still missing); package unused today | **DROP** direct dep (FullCalendar may still bring its own transitively) | | **`zone.js`** 0.16.2 | ~13 KB gz if loaded | Not imported; zoneless boot | Leftover | **DROP** from our deps; confirm Storybook/tests don’t still pull it | | **`asn1js`** ^3.0.10 | ~16 KB gz | **No imports** — voxel uses custom `ASN1.ts` (+ asset) | No ASN.1 platform API | **DROP** npm package; keep custom parser | | **`bigint-mod-arith`** ^3.3.1 | ~1 KB gz npm | **npm unused** — code imports vendored `util/bigint-mod-arith.ts` from `CryptManager.ts` | No `BigInt.modPow` | **DROP** npm package; keep vendored `modPow` | | **`uuid`** ^14.0.1 | ~0.4 KB gz v4 | Sole import: `menu-bar.component.ts` → `guid = uuidv4()` — **appears unused in template** | `crypto.randomUUID()` — Baseline | **DROP** — swap or delete `guid` | | **`js-sha1`** ^0.7.0 | ~2.6 KB gz (+ vendored asset) | Voxel `Authentication.createServerHash` | `crypto.subtle.digest("SHA-1", …)` — Baseline for digest | **DROP** — keep Minecraft signed-hex post-processing; hash step becomes async | | **`@spikersoft/shared-utils-crc32`** | tiny | **No production consumers** (alias + self-tests only) | No CRC-32 browser API | **DROP** unused leaf lib (or wire it later) | Also noted as likely unused direct deps in an earlier pass (confirm dynamic import / assets before delete): **`mermaid`**, **`ngx-socket-io`**, **`avif.js`**, **`three-addons`**. Real AVIF path is `@jsquash/avif`. --- ## Strong “maybe replace with built-ins” | Package / pattern | Why it exists | Native angle | Caveat | |---|---|---|---| | **`fflate`** ^0.8.3 (~12–22 KB gz) | x86 playground sync gzip for localStorage + share-URL parity with upstream `x64.halb.it` | `CompressionStream("gzip")` / `DecompressionStream` — Baseline (Safari 16.4+) | Async rewrite; gzip header `mtime`/`filename` must stay byte-compatible with share URLs | | **`pako`** ^3.0.1 (~14 KB gz; fat ES5 asset also present) | Voxel `NetworkManager` sync zlib inflate/deflate on hot packet path | `CompressionStream("deflate")` / decompress — Baseline | Sync → async forces packet pipeline redesign; confirm zlib vs `deflate-raw`; prefer dropping fat asset if npm import is real | | **Custom AES-CFB** (`wasm-voxel/.../aes.ts`) | Minecraft login encryption | SubtleCrypto has CBC/GCM/CTR — **not CFB** | **KEEP** | | **`ngx-mask`** ^22.1.0 (~44 KB gz) | Global `provideEnvironmentNgxMask()` in `main.ts`; only Marks phone fields | No input-mask API | **MAYBE** custom formatter, or at least move provider into Marks lazy route | | **`JSON.parse(JSON.stringify(...))` clones** | e.g. rete/quicktype | `structuredClone()` — Baseline | Easy cleanup | --- ## Keep — no real browser replacement | Area | Packages / code | Why keep | |---|---|---| | Git playground | `isomorphic-git`, `lightning-fs`, `wasm-git` | OPFS = storage, not Git. Note: wasm-git has OPFS builds (`lg2_opfs*`) — possible evolution to drop lightning-fs IndexedDB layer later (#865-adjacent) | | Archives | `jszip` | Compression Streams ≠ ZIP container | | Game protocol | `@msgpack/msgpack` | Must match .NET server wire format | | QR | `ng-qrcode` | `BarcodeDetector` is decode-only | | EPUB XSS | `dompurify` (#409) | HTML Sanitizer / `setHTML` **not Baseline** — Safari still missing | | Streaming | `hls.js` + `ovenplayer` | OvenPlayer expects hls.js global | | Tours / engines | intro.js, Monaco, Blockly, Rete, Three, Leaflet, Keycloak, SignalR, PDF viewer, Tesseract, DuckDB, etc. | Product features | | `tslib` | Angular/TS emit helpers | Ecosystem expectation | | Custom voxel crypto | `ASN1`, AES-CFB, Minecraft `UUID` | Protocol-specific; only `js-sha1` is the easy native swap | | `pdfjs-dist` | Likely assets for extended PDF viewer | Verify before deleting | --- ## Suggested execution order 1. **Dead deps:** `process`, `temporal-polyfill` (direct), `asn1js`, `bigint-mod-arith` (npm), `zone.js` (our dep), unused `crc32` lib; plus audit `mermaid` / `ngx-socket-io` / `avif.js` / `three-addons` 2. **One-liners:** `uuid` → delete/`crypto.randomUUID()`; `js-sha1` → `crypto.subtle.digest("SHA-1")` (+ remove vendored `sha1.min.js` if unused) 3. **Optional:** `fflate` → CompressionStream (share-URL byte parity); scope `ngx-mask` out of `main.ts` 4. **Harder:** `pako` on Minecraft packets 5. **Wait:** `dompurify` until Safari ships Sanitizer API ### Success metrics - Direct dependency count down; no production import of removed packages - Voxel join/auth works without `js-sha1` - Menu-bar behavior unchanged (or dead `guid` removed) - EPUB XSS tests (#409) still green if DOMPurify untouched - Optional bundle delta on affected lazy chunks --- ## Prime examples ### `js-sha1` → Web Crypto ```ts // today const bytes = sha1.create().update(...).update(...).update(...).digest(); // native const digest = new Uint8Array(await crypto.subtle.digest("SHA-1", concatenatedBytes)); // keep existing Minecraft sign/hex post-processing ``` ### `uuid` → `crypto.randomUUID()` (or delete unused `guid`) Single remaining npm import in `menu-bar.component.ts`; everywhere else already migrated. --- ## Ask 1. Approve a dead-deps + `uuid`/`js-sha1` cleanup PR (low risk). 2. Optionally schedule `fflate` → `CompressionStream` spike (+ `ngx-mask` main-bundle scoping). 3. Do **not** chase DOMPurify / AES-CFB / git / zip / msgpack / heavy engines for “native replace” — wrong ROI or no API.
spikerj added the enhancement label 2026-07-27 02:46:14 +00:00
Sign in to join this conversation.