Skip to main content

Cutting FightCamp Mobile Load Time from 10s to 2s

A winding road through a lush green forest
Jan 11, 20262 min readNext.js, Vue.js, Nuxt.js, Lighthouse, Mobile, CDN, Webpack

I cut FightCamp's mobile load time from 10 seconds to 2 and dropped the mobile bounce rate by 39%, recovering more than half the visitors who used to leave before the page finished rendering. The site's growth after the pandemic had outpaced its web infrastructure: mobile was over 70% of traffic, those users sat through 10-plus-second loads, Lighthouse scores were stuck in the 30s and 40s, and the content team filed around ten engineering requests a week just to update marketing pages. I owned the fixes end to end, from how images and video were delivered to the build pipeline and the self-serve CMS that got marketing off the engineering backlog.

Where the time was going

I found the problems on an R&D Friday and got the go-ahead to dig in. Lighthouse, Chrome DevTools, and a bundle analyzer kept pointing at the same culprits: HD images served at full size no matter the viewport, videos auto-downloading 500-800MB on page load, duplicate libraries bloating a 650-800KB bundle, no lazy loading anywhere, and missing dimensions that left layouts shifting as content arrived.

The fixes

Images and video were the bulk of the payload, so they went first. I built one centralized image component backed by Storyblok with fallback providers, wired up viewport-dependent srcset so a phone never downloaded a desktop image, and added lazy loading with explicit dimensions so layouts stopped shifting. For video I wrote a lazy-loading component on the Intersection Observer API that kept off-screen videos from playing or downloading, and served multiple S3-hosted quality levels that cut payloads from 500-800MB to under 300MB on MP4 and 150MB on WebM.

The bundle came next. I tracked down and removed duplicate libraries, turned on webpack tree-shaking and dynamic imports, and tuned the Nuxt.js production build, which brought it from 650-800KB down to around 300KB.

The last piece fixed the ten-requests-a-week problem at its source. I pulled the shared patterns out of seven marketing pages, extended the UI component library with 10-plus CMS-connected components documented in Storybook and backed by Jest, and integrated Storyblok so marketing could publish without an engineer in the loop. On top of it I built configurable A/B-test components wired to Google Optimize, so marketing ran their own quarterly copy, image, video, and offer tests.

The results

First Contentful Paint (Mobile)~80% faster

Before

8-12s

After

1.8-2.5s

Largest Contentful Paint~63% faster

Before

15-20s

After

5-8s

Total Blocking Time~70% reduction

Before

3-4s

After

0.8-1.3s

Cumulative Layout Shift~79% reduction

Before

3-6s

After

0.6-1.25s

Speed Index~60% faster

Before

11-14s

After

4-6s

Lighthouse Score+40 points

Before

32-43

After

~80

Bundle Size~62% reduction

Before

650-800KB

After

250-300KB

Mobile Bounce Rate~39% reduction

Before

60-75%

After

37-45%

Engineering Requests80% reduction

Before

~10/week

After

~2/week

What I took from it

Performance turned out to be a business metric: that 39% drop in bounce fed straight into acquisition during a critical growth phase. And the highest-leverage work wasn't the load-time tuning at all; it was the CMS that took marketing off the engineering backlog and sped both teams up at once.