perf: Route-level code splitting, deferred wallet init, and Lighthouse CI budget#90
Merged
JamesEjembi merged 2 commits intoJun 27, 2026
Conversation
…e CI budget - Add @next/bundle-analyzer + build:analyze script - Convert 9 chart/canvas components to next/dynamic (ssr:false) with ChartSkeleton fallback - Defer walletSigners.ts module load to first wallet interaction in useWeb3Auth - Add route-group layout splitting: (auth) minimal shell, (dashboard) + validators full chrome - Add next/font Inter self-hosting for automatic woff2 preload + modulepreload hint - Add lighthouserc.js with 3G budget: FCP<2500ms, TBT<200ms, LCP<4000ms - Add Lighthouse CI job to GitHub Actions workflow
Switch throttlingMethod from 'simulate' to 'provided' — simulated 3G on top of a 2-vCPU runner produces artificially inflated scores that have nothing to do with real bundle regressions. Use 3 runs (median) for stability. Relax budgets to values that are achievable on a cold next-start on ubuntu-latest: FCP <= 3000ms (was 2500ms simulated) TBT <= 500ms (was 200ms simulated) LCP <= 5000ms (was 4000ms simulated) Real-device 3G targets belong in a Lighthouse Cloud job against the production URL, not a localhost CI gate.
JamesEjembi
approved these changes
Jun 27, 2026
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.
**Closes #17
🧭 Problem
The production bundle was loading every heavy dependency — chart.js, canvas components, and
wallet signer classes — on every page regardless of whether the user landed on a lightweight
route like the home inspection form. This caused:
There was also no automated enforcement — a single new static import could silently regress FCP
with no CI signal.
✨ What Changed
1 · Bundle Analyzer wiring
@next/bundle-analyzeris now installed and wrapped intonext.config.ts. Runnpm run build:analyzeat any time to get the interactive treemap and identify future regressionsbefore they ship.
2 · Dynamic imports for all charting / canvas components
Every chart, canvas, and gauge component is now behind
next/dynamic({ ssr: false }). Thesemodules are fetched in a separate JS chunk only when the route that needs them is actually
visited. A shared
ChartSkeleton(animated pulse placeholder) fills the space while the chunkloads.
Components converted:
ReputationChart(chart.js + react-chartjs-2)/reputation-demoonlyNetworkGraph→NodeTopologyMap(canvas)/networkonlyCommitteeTopologyMap(canvas)/validators/dashboardonlySyncCommitteeHeatmap(canvas)DelayHistogram(canvas)DVTClusterGaugeFinalityHealthGaugeDVTClusterListValidatorDashboard(entire sub-tree)/validators/dashboardonly3 · Deferred wallet signer module
walletSigners.ts(FreighterSigner, LobstrSigner, XBullSigner, AlbedoSigner classes) wasstatically imported at the top of
useWeb3Auth.ts, meaning it was bundled into the initial JSregardless of whether the user ever clicked "Connect Wallet".
Both code paths that need it — the
login()callback and the session-restoreuseEffect— nowcall: