
Facebook’s redesign introduced a sophisticated approach to code-splitting that fundamentally rethought how JavaScript is delivered to users. By splitting a 500 KB bundle into three strategic tiers, Facebook reduced initial page load times by 75-90%, a breakthrough that’s now considered industry best practice for modern web applications.
The Problem: Impact of JavaScript Bundle Size
Traditional single-page applications (SPA) bundle all their JavaScript together into one or a few large files. A user visit to this page technically means a download, parse, and execution exercise for the browser before the page becomes interactive. Imagine processing a 500 KB JavaScript page with Facebook’s old approach. An entire bundle download would be required before any meaningful content could be seen, impacting key performance metrics such as Time to First Paint (FP) and Time to Interactive (TTI).
- FP — Measures when the browser renders any pixels to the screen.
- TTI — Measures when the page becomes fully interactive.
Every additional second of load time significantly impacts user retention. Studies show that 53% of mobile users abandon websites that take longer than 3 seconds to load, making bundle size optimization not just a technical concern but a business imperative.
The Solution: JavaScript Loading Tiers
Facebook’s revolutionary approach splits the JavaScript into three distinct tiers, each serving a specific purpose in the page loading lifecycle. Each tier contains code that is statically analyzable and declaratively expressed, allowing engineers to make intelligent optimization decisions with their build tools.
Tier 1: Critical Initial Render (Core Layout & Skeletons)
Considering the example of the 500 KB page. This tier contains only 50 KB of it. The absolute minimum needed for the first paint (FP). The most commonly used solution, which renders silver-grey shiny UI components to indicate loading.
Tier 1 takes care of:
- Basic page layout and navigation framework
- UI skeleton components and loading placeholders
- Critical path code only
Completely excluding full component libraries, interactive features, post-rendering code, and analytics and logging features.
Image taken from: https://engineering.fb.com
A basic implementation of this is shown below using ReactJS with Suspense.
Skeleton components are lightweight, pure JavaScript that creates placeholder shapes matching the final layout. This satisfies a critical user experience principle: Provide immediate visual feedback.
A performance timeline for Tier 1 might look something like this:
| Event | Time | Data Downloaded | User Sees |
|---|---|---|---|
| Request initiated | 0ms | 0 KB | Blank page |
| HTML Arrives | ~100ms | 20 KB | Loading... |
| Tier 1 JS downloads | ~300-500ms | 50 KB | Skeleton UI |
| First Paint | ~500-700ms | 50 KB | Gray placeholders |
Tier 2: Complete Above-the-Fold Rendering
This tier brings the 500 KB page to 200 KB by adding 150 KB of additional information, enough to render all above-the-fold content completely. After Tier 2 finishes loading, nothing visible on the screen should change due to code loading.
Tier 2 takes care of:
- Full rendering code for all visible components
- Image display components (PhotoComponent, VideoComponent)
- Event handlers for visible interactive elements
- All data rendering logic
Completely excluding below-the-fold components, modals and overlays, analytics, and user activity tracking.
When scrolling through the News Feed, Tier 2 ensures that each post displays completely with all the attachments, reaction buttons, user profile pictures, and top comments. The key metric here is visual completion — the user should see no jumping, reflowing, or appearing elements after Tier 2 loads.
A basic implementation with Relay (a GraphQL client for React) for component-based code splitting:
This architecture is particularly powerful because Relay knows statically which rendering code is needed for each data type. If the server returns only PhotoPost and TextPost types, then the VideoComponent code isn’t sent to the browser.
Tier 3: Background Enhancement
Out of the 500 KB, this tier brings in the remaining 300 KB — code that enhances the experience but doesn’t affect what pixels appear on the screen. This tier loads after the page is visually complete and interactive.
Tier 3 takes care of:
- Analytics and logging code — Recording that you opened the app, the time spent, and engagement metrics.
- Real-time subscription for live updates — Subscriptions that listen for new posts from friends, enabling live feed refresh without user intervention.
- Extended interactive features
- Tracking pixels — Code that tracks which posts users hover over, pause on while scrolling, or view for extended periods.
- Ad serving code — With ad refreshing that periodically fetches new ads to display in the feed sidebar.
- Background prefetching logic — Logic that anticipates which profiles or pages the user might click next and prefetches their code (detects hovers, mouse clicks, and other events to predict intent)
A JavaScript utility for this might look like this:
Note: importForAfterDisplay is Facebook’s internal utility that ensures import after display.
This tier-based approach particularly benefits mobile users. On a typical 4G connection, downloading a 500 KB bundle immediately means 8-10 seconds of waiting. With Tier 3, users achieve a fully interactive experience in 2-3 seconds, then gain enhanced features (analytics, real-time updates) in the background without noticing any lag or battery drain from aggressive downloads.
Conclusion
Deliver what users need, when they need it. This is a powerful principle demonstrated by Facebook’s three-tier JavaScript loading architecture. But this is just one of the things that Facebook did to optimize its new application’s performance.
Find out what more they did by following this link to Facebook's official blog post.
Meanwhile, I will find out what more I can learn and share with you by diving deeper into the concept.