Case Study
React Vite Code Splitting Mobile Performance

70% Less Memory.
Zero Jank.

How we optimized a React mobile game for low-end devices through strategic bundle splitting — cutting memory by 70% and eliminating frame drops.

The Problem

Bot Simulator is a mobile-first robot factory game built with React and Vite. Players manage autonomous robots, unlock tiers, customize skins, and compete on leaderboards — all rendered in real-time with Web Workers handling the simulation.

The game shipped as a single 451 KB JavaScript bundle. Every modal panel — achievements, leaderboards, game-over screens, robot selection — was loaded upfront on startup, even though players might never open most of them in a session.

On low-end Android devices (the majority of our global audience), this meant 21.5 MB of heap memory consumed before the first robot even moved. Startup frame drops hit 37 FPS on throttled devices — a noticeable stutter that undermined the game's polished feel.

The Solution

We identified 7 heavy panel components that are only shown conditionally — never on initial load. Using React's built-in lazy loading and Suspense boundaries, we split each into its own chunk that loads on-demand when the player first opens it.

📦

Lazy Loading

React.lazy() defers parsing and execution of panel code until the player actually needs it.

Suspense Boundaries

Each panel gets a Suspense wrapper with null fallback — chunks load so fast users see no spinner.

🎯

Conditional Mounting

Components that used isOpen props were refactored to conditional renders, ensuring the chunk isn't fetched until truly needed.

Benchmark Results

The Numbers Speak

Tested on simulated Moto G Power · 4x CPU throttle · 3G network

Memory Usage
0%
21.5 MB 6.4 MB
P5 FPS (Jank Floor)
0%
37.6 74.1 FPS
Initial Bundle
0%
129 KB gz 122 KB gz
First Contentful Paint
0ms
928ms 904ms
Long Tasks (Jank)
0
Zero main-thread blocking during gameplay
Total Blocking Time
0ms
Clean 75 FPS median throughout session
Bundle Size Comparison
Before — Single Chunk 451.66 KB (129.29 KB gzip)
After — Main Chunk 417.80 KB (122.55 KB gzip)
After — Memory (Heap Used) 6.38 MB vs 21.52 MB
7 Lazy-Loaded Chunks (loaded on demand)
RobotSelection
1.98 KB gz < 100ms
GameOverOverlay
2.11 KB gz < 100ms
LeaderboardPanel
2.22 KB gz < 100ms
AchievementPanel
1.97 KB gz < 100ms
DailyRewardModal
1.64 KB gz < 100ms
LevelUpModal
1.41 KB gz < 100ms
UsernameInput
1.35 KB gz < 100ms
Test Environment

Benchmarked on Real-World Conditions

We didn't test on a MacBook Pro with gigabit fiber. We simulated the devices our actual players use.

📱
Moto G Power 375 × 667 viewport
🐢
4x CPU Throttle Simulates low-end SoC
📶
3G Network 1.5 Mbps / 40ms RTT
🧊
Cold Cache No prior visits

Want This Kind of Engineering?

We obsess over performance so your users don't have to think about it.

Start a Project