You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Code-split the main bundle before the JS budget cap bites again #140
main-*.js is at 96–98% of its budget (currently 700 kB, raised twice this month for new drivers) and vite's own build warning already flags it as over the 500 kB chunk-size guideline. The budget has been raised five times in the changelog history; splitting the bundle (dynamic import() for per-brand driver UI, per vite's own suggestion) is due before another driver addition forces a sixth raise.
Work started in PR #1227 (open, awaiting CI). Measured breakdown of the 2,299 kB main chunk before any change: the @openmouse/protocol driver tree is ~1.23 MB, posthog-js ~377 kB, the app itself (with preact) ~688 kB.
posthog loads behind a dynamic import with an event/exception queue (builds without the key tree-shake it out entirely).
The driver registry (all ~96 vendor modules, 320 kB chunk) loads behind a shared dynamic import; controller call sites were already async flows, semantics preserved (tests updated, including the Bridge identity one).
Settings, hardware test, games and the capture/share/what's-new dialogs load on demand.
The size check now bounds main-*.js separately (1.6 MB budget, measured 1,511,619), so registry growth can't ride into the initial load unnoticed, and the total budget didn't need a raise here.
Still open after #1227: ~900 kB of driver code remains in main because controller.ts references ~30 driver classes directly (instanceof tables like NEEDS_OPEN/DM_CLASSES, activeAs checks, the Logitech onboard-profile helpers). Splitting those is the remaining slice — it needs per-brand dynamic boundaries inside controller.ts itself, which is why I kept it out of the first PR.
Follow-up landed: the controller half of the lazy-driver split is up in #1230.
The measured scope from the last update turned out to be mostly controller-side, so this PR takes that slice:
Controller imported ~59 protocol driver modules statically: ~874 kB of driver code in MAIN (logitech 89 kB, atk 93 kB, keychron 84 kB, mchose 57 kB, razer 55 kB, lamzu 46 kB, endgame 41 kB, …). App-only MAIN measured ~637–643 kB.
New src/device/driver-classes.ts merges those modules behind one shared dynamic import. Activation/classification flows (activateClient, refreshSidebar, selectAuthorizedDevice, requestSupportedClient, HID connect, previews) await it; the per-brand accessors stay synchronous by reading the loaded table at call time, reporting "no client" pre-load — which matches reality, since nothing can be active before those flows run.
Device-gated value helpers read strictly and throw if ever called early; the boot-render rate options list is the one deliberate neutral site (the smoke test caught exactly that race, now fixed).
Result: MAIN 1,513,424 → 957,733 bytes (-37%), all 405 tests green, bundle-size check OK. VENDOR_ID/RAZER_PRODUCTS stay static (their modules are already in MAIN via the WebHID picker filters).
What remains from this issue's list: the cards' own static protocol value imports under src/features/ (PerformanceCards, AdvancedCards, DpiCard, Profiles, setup-code, capture…) — that is the final slice, tracked for a follow-up PR. The MAIN budget can be tightened to the new measurement once that lands.
Activity
jazzstack commentedon Oct 25, 2026
Work started in PR #1227 (open, awaiting CI). Measured breakdown of the 2,299 kB main chunk before any change: the
@openmouse/protocoldriver tree is ~1.23 MB, posthog-js ~377 kB, the app itself (with preact) ~688 kB.In #1227:
main-*.jsseparately (1.6 MB budget, measured 1,511,619), so registry growth can't ride into the initial load unnoticed, and the total budget didn't need a raise here.Still open after #1227: ~900 kB of driver code remains in main because
controller.tsreferences ~30 driver classes directly (instanceoftables likeNEEDS_OPEN/DM_CLASSES,activeAschecks, the Logitech onboard-profile helpers). Splitting those is the remaining slice — it needs per-brand dynamic boundaries insidecontroller.tsitself, which is why I kept it out of the first PR.perf(bundle): split posthog, the driver registry and secondary pages …
jazzstack commentedon Oct 25, 2026
Follow-up landed: the controller half of the lazy-driver split is up in #1230.
The measured scope from the last update turned out to be mostly controller-side, so this PR takes that slice:
src/device/driver-classes.tsmerges those modules behind one shared dynamic import. Activation/classification flows (activateClient,refreshSidebar,selectAuthorizedDevice,requestSupportedClient, HID connect, previews) await it; the per-brand accessors stay synchronous by reading the loaded table at call time, reporting "no client" pre-load — which matches reality, since nothing can be active before those flows run.Result: MAIN 1,513,424 → 957,733 bytes (-37%), all 405 tests green, bundle-size check OK.
VENDOR_ID/RAZER_PRODUCTSstay static (their modules are already in MAIN via the WebHID picker filters).What remains from this issue's list: the cards' own static protocol value imports under
src/features/(PerformanceCards, AdvancedCards, DpiCard, Profiles, setup-code, capture…) — that is the final slice, tracked for a follow-up PR. The MAIN budget can be tightened to the new measurement once that lands.perf(device): load driver identity modules behind a lazy chunk (#1230)