Rewriting Facebook.com
Facebook has evolved from its initial PHP server-side rendered website over the past 16 years. The external environment for web development has changed dramatically, and the cost of developing new features on the old architecture is increasing. To achieve an "app-like experience" and outstanding performance, they rewrote the entire main website using React and Relay, based on two principles — "as little as possible, as early as possible" and "enhancing developer experience to serve user experience."
Applying these two principles to four main elements (CSS, JavaScript, data, navigation) yields the following insights:
- Improve CSS
- Atomic CSS: Using atomic class CSS generated at build time reduced the homepage's CSS by 80% — because the number of entries in this CSS approaches
log N
— the total amount of styles grows with unique styles rather than the number of styles and features written in the code. We at Uber use Styletron for this purpose. - CSS-in-JavaScript: Using methods like
stylex.create({})
to generate styles for components, colocating them with the components to enhance removability and make styles easier to maintain. - Consistently use
rem
for better scaling experience, automatically convertingpx
torem
at build time. - Implement dark mode using CSS variables.
- Use inline SVG in HTML as icons to solve the flash issue of delayed icon rendering.
- Atomic CSS: Using atomic class CSS generated at build time reduced the homepage's CSS by 80% — because the number of entries in this CSS approaches
- Split JavaScript to optimize performance
- Incrementally load code, breaking down 500 KB of total code into 50 KB Tier 1, 150 KB Tier 2, and 300 KB Tier 3, corresponding to skeleton content, initial screen content, and non-UI content, loading them as needed.
- Load experimental code only when necessary.
- Load corresponding code based on data, such as loading image components for image data and video components for video data.
- Budget the size of JavaScript and strictly monitor changes in code size.
- Load data as early as possible
- Preloading: Using
Relay
to immediately know the data needed for the initial screen, streaming this data while downloading the code. - Reduce round trips using streaming.
- Delay loading data that is not currently needed.
- Preloading: Using
- Define route mapping to accelerate navigation
- Obtain route definitions as early as possible.
- Pre-fetch resources early, starting when hovering or focusing. After navigation changes, if loading is not complete, retain the current page using React Suspense transitions until loading is finished before switching. This keeps the experience consistent with standard browser behavior.
- Download code and data in parallel. Typically, code is downloaded first followed by data, which is serial; Facebook allows data and code to download simultaneously in one round trip.