Skip to content

Lazy-load translations and batch selection deletion bookkeeping#2102

Merged
frankrousseau merged 2 commits into
cgwire:mainfrom
frankrousseau:audit-arch2-perf4-2026-07
Jul 10, 2026
Merged

Lazy-load translations and batch selection deletion bookkeeping#2102
frankrousseau merged 2 commits into
cgwire:mainfrom
frankrousseau:audit-arch2-perf4-2026-07

Conversation

@frankrousseau

Copy link
Copy Markdown
Contributor

Problems

  • All 15 translated locales were bundled eagerly into the main chunk: ~1.5 MB minified shipped to every user for languages they never open, putting the entry bundle at ~2.3 MB.
  • deleteSelectedShots dispatched one deleteShot per selected shot, and each commit paid three full list passes (cache.shots, cache.result, displayedShots) — deleting N shots from a list of M cost O(N×M) of store work on top of the N HTTP calls. deleteSelectedAssets had the identical pattern. A failure mid-loop also left no trace of what had already been deleted.

Solutions

  • Locales now load through dynamic imports — one chunk per language (~100 kB each), registered via setLocaleMessage when setLocale asks for it. The main chunk drops from ~2.3 MB to 763 kB. English and its production-style overlays (en_nft, en_video-game) stay eager since en is the fallback locale and App.vue switches to the overlays synchronously. setLocale keeps its signature but returns a promise; a pending-language guard keeps a slow older chunk from overriding a newer switch.
  • Deletion requests stay serial — no parallel hammering of the server — but the store bookkeeping accumulates and lands in a single bulk mutation (REMOVE_SHOTS / REMOVE_ASSETS): one filter pass per list and one stats recompute, whatever the selection size. A finally block commits what the server actually deleted even when a request fails mid-loop, so the UI never desyncs on partial failure. Two deliberate improvements over the sequential path: the displayed count is recomputed after pure removals (it previously went stale until the next search), and canceled flags are set before the assets stats recompute so canceled assets stop counting immediately.

Tests: bulk/sequential equivalence pinned for shots, serial requests asserted (maxInFlight === 1), single-commit and partial-failure paths covered for both stores; lang spec extended with the lazy-load and rapid-switch cases. Full suite: 88 files, 1038 tests, 0 failures.

All 15 translated locales were bundled eagerly into the main chunk:
~1.5 MB minified shipped to every user for languages they never open.
Locales now load through dynamic imports — one chunk per language,
registered via setLocaleMessage when setLocale asks for it. The main
chunk drops from ~2.3 MB to 763 kB.

English and its production-style overlays (en_nft, en_video-game) stay
eager: en is the fallback locale and App.vue switches to the overlays
synchronously. setLocale keeps its signature but returns a promise that
resolves once the language is applied; a pending-language guard keeps a
slow older chunk from overriding a newer switch.

Also excludes .claude/ agent worktrees from vitest discovery (same hunk
as on the audit-tests branch; merges cleanly).
deleteSelectedShots dispatched one deleteShot per selected shot: each
commit paid three full list passes (cache.shots, cache.result,
displayedShots), so deleting N shots from a list of M cost O(N×M) on top
of the N HTTP calls. Assets had the identical pattern.

The HTTP requests stay serial — no parallel hammering of the server —
but the store bookkeeping now accumulates and lands in a single bulk
mutation (REMOVE_SHOTS / REMOVE_ASSETS): one filter pass per list, one
stats recompute, whatever the selection size. A finally block commits
what the server actually deleted even when a request fails mid-loop, so
the UI never desyncs on partial failure.

Two deliberate behavior improvements over the sequential path: the
displayed count is recomputed after pure removals (it previously went
stale until the next search), and canceled flags are set before the
assets stats recompute so canceled assets stop counting immediately.

The shots spec pins bulk/sequential equivalence; both specs check the
requests stay serial, the single commit, and the partial-failure path.
@frankrousseau frankrousseau force-pushed the audit-arch2-perf4-2026-07 branch from 2c366a5 to a8e3d7d Compare July 10, 2026 13:17
@frankrousseau frankrousseau merged commit 38e06e1 into cgwire:main Jul 10, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant