KeyboardTest.tech is almost entirely client-side JavaScript — the whole point is real-time keyboard event handling in the browser. That's exactly the kind of app that can quietly balloon in bundle size and feel sluggish on load if you're not paying attention. Here's what I actually did to keep it fast, and a couple of things I tried that didn't help as much as expected.
Static generation for everything that doesn't need to be dynamic
Since the actual testing logic runs entirely client-side, there's no reason for the tool pages themselves to hit a server on every request. Static generation via Next.js App Router means the HTML shell ships instantly, and the interactive bits hydrate in after — the user sees the page immediately instead of waiting on a render round-trip.
Splitting client components aggressively
Not every part of a tool page needs to be a client component. The static content — headings, FAQ text, the "how to use this" copy — stays as server-rendered content, while only the actual interactive keyboard UI is marked "use client". This keeps the client-side JS bundle scoped to what genuinely needs interactivity instead of hydrating the entire page.
The thing that surprised me: font loading mattered more than I expected
Early versions had a visible layout shift from web font loading. Switching to font-display: swap and self-hosting the fonts (rather than a third-party font CDN round-trip) fixed most of the perceived jank — this had a bigger visible impact on "does this feel fast" than several JS optimizations combined.
What didn't help as much as I hoped: code-splitting the event-handling logic
I expected lazy-loading the keyboard event detection logic (ghosting/chatter/rollover) to meaningfully cut initial bundle size. In practice, it's small enough that the added complexity of a dynamic import wasn't worth the marginal savings — sometimes the "obviously correct" optimization isn't worth the engineering overhead for the actual bytes saved. Worth measuring before assuming.
Debounced rendering for the visual key-state UI
Every keydown/keyup was originally triggering a full re-render of the on-screen keyboard. Batching state updates and only re-rendering the specific key components that changed (rather than the whole keyboard grid) made multi-key stress-testing noticeably smoother, especially on lower-end devices.
Top comments (0)