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