跳到主要内容

重写 Facebook.com

Facebook 从最初的 PHP 服务端渲染网站发展至今已经 16 个年头,Web 开发的外部环境已经是沧海桑田,在老构架上开发新 Feature 的成本也越来越高。为了得到“App 的体验”以及卓越的性能, 他们用 React 和 Relay 重写了整个主网站,基于两个原则 —— “尽可能少尽可能早”、“提升开发体验以服务用户体验”。

将这两个原则应用到四个主要元素 (CSS,JavaScript,数据,导航) 上,得到如下经验

  1. 改进 CSS
    1. Atomic CSS: 使用 Build 时生成的原子类 CSS 将首页的 CSS 减少 80% - 因为这种 CSS 的条目的数量接近 log N——样式的总量是随着独特的样式增长的,而不是跟着代码里面写的样式和 feature 的数量增长的。我们 Uber 就使用的 Styletron 来做这件事情。
    2. CSS-in-JavaScript: 用类似于 stylex.create({}) 这种方法来为组件生成 Style,跟组件放到一起,以增加可删除性,让样式更容易被维护。
    3. 统一使用 rem 让缩放的时候体验更好, Build 时自动将 px 转化成 rem.
    4. 使用 CSS 变量实现黑暗模式
    5. 使用 HTML 内嵌 SVG 作为图标,解决图标延迟渲染的一闪问题
  2. 分拆 JavaScript 以优化性能
    1. 增量式加载代码,把 500 KB 的总代码,分成 50KB Tier 1,150KB Tier 2, 300KB Tier 3,分别对应骨架内容、首屏内容 、非 UI 内容,然后按需加载。
    2. 只在需要的时候加载实验代码
    3. 根据数据加载相应的代码,比如图片数据加载图片组件、视频数据加载视频组件
    4. 给 JavaScript 的大小做预算,严格监视代码尺寸的变化
  3. 尽早载入数据
    1. 预加载:用 Relay 能够立马知道首屏所需要的数据,在下载代码的同时,也 stream 这些数据
    2. 用 stream 的方式减少 round trips
    3. 延迟加载现在不需要的数据
  4. 定义路由 map 以加速导航
    1. 尽早获得路由的定义
    2. 尽早预先获取资源,在 hover 或者 focus 的时候就开始了,导航变化之后,如果还没有加载完,先用 React Suspense transitions 保留当前页面,只有加载完之后才真正切换。这样就能跟标准的浏览器体验保持一致。
    3. 并行下载代码和数据。通常是先下载代码再下载数据,这样是串行的;FB 让数据和代码在一个 round trip 里面同时下载。