Skip to content

Code-split the main bundle before the JS budget cap bites again #140

Open

Description

@snekxs

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.

Activity

  1. added this to the 1.0 Beta milestone on Aug 30, 2026
  2. jazzstack commented on Oct 25, 2026

    @jazzstack
    Contributor

    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.

    In #1227:

    • 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.

  3. jazzstack commented on Oct 25, 2026

    @jazzstack
    Contributor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions