Where the time goes on launch
- App start and splash — the Android process starts and the WebView initialises. Fixed cost, a few hundred milliseconds on a mid-range phone.
- Reading your files — fast; they are local. Size matters less here than on the web.
- Parsing and running JavaScript — the dominant cost for framework apps. A 1.5 MB bundle can take a second or more to parse on a budget phone, network or not.
- Layout and images — decoding large images and reflowing when they arrive.
So for speed, the lever is JavaScript. For download size, it is media.
Size: what to cut first
| Offender | Typical saving | Fix |
|---|---|---|
| Photos at camera resolution | 70–90% | Resize to ≤ 1920 px and convert to WebP |
| Background / hero video | 5–40 MB | 720p re-encode, or stream from a URL |
| Source maps | ≈ size of your JS | Delete *.map |
| Fonts in TTF/OTF/EOT + WOFF + WOFF2 | 50–75% of font weight | Keep WOFF2 only; subset to the languages you use |
| WAV audio | ≈ 90% | OGG or MP3 at 96–128 kbps |
| Whole icon libraries | 100s of KB | Import only the icons you use, or inline SVG |
Speed: first screen first
- Split the bundle. Route-level code splitting (
React.lazy, Vue async components, dynamicimport()) means the first screen parses only its own code. Chunks load from local files, so there is no network penalty for splitting. - Defer the rest. Analytics, chat widgets and anything below the fold:
defer, or load after the first paint withrequestIdleCallback. - Render something immediately. A static skeleton in
index.html— even just the header and background colour — makes the hand-off from splash to page feel instant while the framework boots. - Match the splash. Set the builder's splash and theme colour to your page's background so the transition is seamless instead of flashing white.
Smoothness
- Give every image
widthandheightattributes (oraspect-ratioin CSS) so the page does not jump as they decode. - Animate
transformandopacity, nottop,heightorbox-shadow. - Use
loading="lazy"on off-screen images in long lists. - Keep scroll handlers passive:
addEventListener('scroll', fn, { passive: true }).
Test on the phone your users have
Your phone is probably faster than your median user's. A three-year-old budget Android device with 3–4 GB of RAM is a far more honest benchmark; if the app feels fine there, it feels fine everywhere. In desktop Chrome, DevTools' Performance panel with 4× CPU throttling is a rough stand-in.