perf(spa): code-split routes so D3/marked leave the initial bundle (part 1 of #101)#112
Merged
Conversation
) Convert the 8 top-level routes in Shell.tsx from static imports to lazy()/Suspense. Each route becomes its own chunk fetched on first visit, so route-only heavy deps no longer ship on first paint: - D3 (d3-force/drag/scale/selection) — only in Memory -> own 64 kB chunk - marked + DOMPurify — only in Docs -> own 71 kB chunk Entry chunk: 274.58 kB (90.55 kB gzip, single file) -> 73 kB entry + per-route chunks; D3/marked excluded from the initial download and loaded on demand. A small Suspense fallback (.route-loading, reduced-motion aware) covers the brief chunk fetch on route switch. app.test.tsx's route-navigation test gets a longer findBy timeout since routes now resolve through a dynamic import. This is part 1 of #101 (the lazy-loading half). The polling-unification half is intentionally deferred to land with the SSE work in #93 — the real target there is the module-level store pollers, which should become event-driven rather than merely moved to usePoll. Tests: 113 passing (20 files). tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Code-splits the SPA's top-level routes so route-only heavy dependencies leave the initial bundle — part 1 of #101 (the lazy-loading half).
src/routes/Shell.tsx: the 8 routes go from static imports tolazy()+Suspense. Each becomes its own chunk fetched on first visit, so:d3-force/drag/scale/selection) — used only by Memory — moves to its own chunk.Measured impact (
yarn build)__data__/velocityDecayconfirmed absent from entry)DOMPurifyconfirmed absent from entry)D3 and marked (~135 kB raw / ~47 kB gzip combined) now download only when Memory/Docs are opened.
Notes
.route-loadingSuspense fallback (reduced-motion aware) covers the brief chunk fetch on route switch; local chunks resolve in a few ms.app.test.tsx's route-navigation test gets a longerfindBytimeout since routes now resolve through a dynamic import (it already navigates to Memory and asserts the heading renders — automated proof the lazy Memory/D3 route still mounts correctly).MoreSheetstays eager (tiny, lives inside the always-mounted BottomSheet).Verification
yarn tsc --noEmitclean.yarn test→ 113 passing (20 files).Scope / what's deferred
Part 2 of #101 — unify polling on
usePoll— is intentionally not in this PR. The real target there is the module-level store pollers (tasks/memory/triggers/metrics), which should become event-driven via/api/events(#93) rather than moved tousePolland then redone. Tracked in the issue + #93.Addresses #101 (part 1).
🤖 Generated with Claude Code