[译] 构建世界上最快的会议网站

这是 JSConf EU 的组织者 Malte Ubl 的客座文章。css

是否是被标题诱惑来啦,但咱们绝对不会让你白来一趟的!我不肯定这必定是世界上最快的会议网站,但我也不肯定它不是;并且我花了一大笔多到不合理的时间试图让它成为世界上最快的会议网站。我也是网络组件库 AMP 的建立者,它能够用于搭建快速可靠的网站,一样,这些网站也是我尝试新技术进行优化的游乐场,而后我能够将它们应用到平常工做中。此外,快速网站有更好的转换率,在咱们的状况下这意味着:卖出更多的门票前端

这个 JSConf EU 网站是搭建在静态网页生成器 wintersmith 上的。若是你知道 Jekyll 是什么,那你必定也会知道什么是 wintersmith。基本上都差很少,它们都基于 Node.js。Wintersmith 还好,默认状况下它不会作什么可怕的事情,可是有一些我须要的东西必须本身构建。android

字体

内联

OMG,我花了好多时间来优化字体性能。你知道怎么拥有比 JSConf 网站更快的字体性能吗?那就去使用系统字体吧,但那样会有些无聊。咱们使用了 Typekit 的字体,它的字体都很赞。Typekit 要求你加载一个 CSS 文件或者 JS 文件,用来告诉网站字体文件在哪里。这对性能来讲太可怕了:加载文件意味着等待网络,而网络速度很慢。因为 DNS 解析,TCP 和 TLS 链接等缘由,添加一个指向第三方主机的 CSS 文件到页面能够轻易地影响首屏渲染时间,可能会有大概 600 ms。咱们修复了这个问题,方法是在构建过程当中下载 CSS 文件,而后在 CSS 中内联它们。问题解决了,咱们赢得了 600 ms。ios

事实证实 Typekit CSS 文件实际上使用了 @import 来添加其余的 CSS 文件。我不肯定这个会不会阻塞渲染,但这个确定很差。原来该文件是空的,对它的请求仅仅用于统计信息的收集。为了不这种状况,我在编写的脚本文件中移除了内联 CSS 中的 @import哈哈,正则),而后在 JavaScript 中保存这个请求的连接,页面加载完毕(不会再影响首评渲染时间)以后,再去请求。git

字体显示

好了,既然咱们已经内联了 Typekit 的 CSS,咱们也能够经过更多的正则表达式轻松地改变它。在 @font-face 规则中添加 font-display: fallback,能够阻止字体绘制时对下载的阻塞,基于上面的缘由咱们在脚本中添加了这样的代码。github

不可变的 URL

我但愿 wintersmith 能有一个真正的资源管道(asset pipeline)。它确实有资源处理程序,但每种资源只有一个。因此,在没有代码重复的状况下,你没法轻松地为 CSS 文件和 SVG 执行操做。但谁关心会议网站的代码重复?web

黑入了 wintersmith,将哈希值插入到全部本地可用的资源 URL 中,并为它们提供了一个在 CDN 中配置的公共路径前缀,用来有效地发出无限的缓存头。一样,咱们的 ServiceWorker 知道它永远没必要担忧这些 URL 过时而且能够永久保留资源。若是你复制咱们的代码,请考虑缩短哈希值。对于咱们这个用例,在现实世界中没有人须要这个完整的 SHA-XXX 串,并且还能在 HTML 中省下至关多的字节。我如今不打算改变它,由于这会破坏全部资源的缓存。正则表达式

CSS

死码消除

JSConf EU 网站使用 Tachyons 做为 CSS 框架。Tachyons 很不错,除了它的体积很大,并且就算是最小的基础包中也具备全部的功能。我安装了一个 CSS 死码消除(DCE)后处理步骤,它能够查看全部静态网站生成器生成的实际标记,而后将从不匹配任何内容的 CSS 选择器都修剪掉。在咱们的例子中,它将 CSS 体积减小了超酷的 85%。后端

内联

既然 CSS 的体积很是小,那么将它内联到每一个页面中就说的过去了。你可能会想“可是缓存怎么办?”很好的问题,可是若是你想在这场关于最快网站的竞赛中获胜,你就没法负担得起冷缓存状态下额外的请求。因此我内联了 CSS,并且事实上咱们能够在 CSS DCE 上作的更好。因此我再次在每一个页面上运行它,对于每一个页面又缩减了额外的 15-25% 的 CSS 体积。浏览器

顺便说一句:先在整个网站运行一次 CSS DCE,而后再在每一页上进行一次该处理是很是有意义的。这是由于对于整个网站来讲 DCE 处理的时间复杂度是 O(全部 HTML 大小 + CSS 大小) ,对于单个页面是 O(页面数量 *(平均 HTML 大小 + CSS 大小)。若是你首先在整个网站上运行优化,CSS 体积的减小可让接下来对于单个页面的优化明显更快 —— 至少若是你能够在首次处理时减小 85% 的体积,就像咱们的例子中实现的那样。

内容管理

大多数静态网站生成器都但愿经过将 markdown 文件放入 git 中来管理网站。JSConf EU 网站使用 Google Spreadsheet 来维护结构化数据(例如演讲者资料)和 Google Docs 来保存像这样的博客文章。虽然这不会让网站运行更快,但它确实使编辑速度更快,因此它仍然能够计入最快的会议网站。例如说这个,就是你如今看到的这篇文章!

做为 Google GSuite 后端(LOL)构建过程的一部分,咱们应该进行图像优化。不幸的是,尚未足够的时间来制做 webp 图像,因此若是你想创建一个更快的会议网站,这确定是个突破口!

ServiceWorker

JSConf 网站有一个基于 Workbox 的 ServiceWorker。ServiceWorker 并不总有益于性能。它们必须安装注册,而后一般还得额外的配置 IndexedDB。这可能花费 100 毫秒。然而,对于会议网站而言,离线功能在性能问题上确定会赛过糟糕的会议 Wi-Fi(咱们的会议 Wi-Fi 一般很出色,但会议室有 1400 人,咱们但愿作好准备)。经过使用 导航预加载来进一步缓解这个问题,在大部分浏览器中导航预加载能够分摊文档网络请求的启动时间。

为了权衡新鲜程度以及离线功能,该网站使用了“网络优先”策略,咱们会首先尝试获取新的文档,若是在 2 秒以内没有响应,咱们会回退到缓存。

由于网站的全部资源都使用了不可变的 URL,ServiceWorker 将永久缓存这些 URL 并始终从缓存(若是可用)提供服务。

动画

你可能已经注意到在咱们的首页上有一个很大的动画 X。很显然,若是没有这个动画,页面的加载速度会更快,可是那样的话还有什么乐趣呢?这个动画是基于 Lottie-Web 库制做的,这是一个由 AirBnB 建立的开源 Adobe AfterEffects 动画网络播放器,被公认为难以置信的赞。不幸的是,它也很庞大。这里的庞大指的是动画运行时间和动画数据自己,后者是一大堆 JSON。咱们加载了 JSON 文件做为动画 JS 的一部分而不是使用 JSON.parse,如此咱们即可以在主线程以外解析这些数据。

脚本加载

JSConf EU 网站实际上加载了一些 JavaScript —— 但它不会阻止页面绘制,咱们内联了交互所须要的每一块代码。这样当浏览器绘制页面的时候,无论外部 JS 是否已经加载完毕,全部关键的交互都已经在起做用了。虽然这个不会让内容安全策略(CSP)满意,可是不要怂,及时行乐,哈哈哈。咱们加载的 JS 文件也不会改变 DOM,即不会触发额外的绘制(固然,除了动画之外),因此不管浏览器首先绘制了什么内容,在发生用户交互以前它都不会发生改变。

预加载

除了乐一乐,咱们但愿你们在这个网站上作的主要事情之一就是买票。这就是为何咱们在页面加载的早期就预先加载了票务支付提供商的登陆页面的缘由,以便当你决定买票(哈哈哈,我以为应该买!)的时候,它就能够马上加载。另外,咱们预加载了从主导航连接到的全部页面,所以在网站内的导航速度很是快。不幸的是,并非全部的浏览器中都有预加载的功能,可是社区最近真的用了不少时间使它能够和 Safari 的双键缓存基础设施兼容,因此咱们有望在全部浏览器中使用它 —— 尽管不是在 JSConf EU 2019 中。

HTTP 级联

这个网站绘制使用了一次 HTTP 往返,而且从不须要获取一个 HTTP 资源用来确认除了主文档以外还须要获取其余内容。这意味着 HTTP 级联的最大深度为 2 次请求。特别是在移动设备上,页面加载时间一般由延迟决定。在这些状况下,具备一个扁平的请求级联意味着网络延迟会带来较少的负面影响,或者让咱们返回到时间复杂度 O 上:在延迟和可用或所需带宽关系很大的状况下,页面加载时间是 O(延迟 * HTTP 级联深度 + 下载内容用时)。可以始终使用 1 次 HTTP 往返绘制意味着在许多状况下页面的加载时间由 DNS 和 TLS 链接决定。这些在实验测试中常常看起来很糟糕。但有了 CDN 对 TLS1.3 甚至 Quic/HTTP3 的支持,真实状况下的性能看起来会好不少,特别是对于那些重复访客。

2019.jsconf.eu 网址的请求数据流
一个很是扁平的 HTTP 级联(右下角是 ServiceWorker 在启动,它不会影响原始页面加载)。

图像加载

OMG,我讨厌加载图像时没有预先知道它们的大小,而且当它们经过网络传输时,它们会推迟页面的显示。在咱们的网站上,全部的图像要么有一个静态的大小,要么使用 padding-top: XX% hack 使图像扩展到全部可用的水平空间。其余人还使用了 intrinsicsize 属性(目前没有浏览器支持)(如此即可以不使用刚才的 hack) 和 懒加载属性(目前也没有浏览器支持)以及decoding=async(目前大部分浏览器支持)来避免图像解码阻塞主进程。

什么是 CSS 中的宽高比?他们说是 padding-top 百分比。Jan 18, 2018

(小小的讽刺警告:上面推文的图片拖慢了页面,可是我把它放在了页面的这个位置,你可能都不会注意到(若是你没有看到这里的话),实在是很差意思)。

总结

就是这样啦。在 2019 年制做快速网站并非一件很难的事情。你只须要这浏览器制造商打好关系,付他们钱就让网站速度更快,在 Twitter 逛一成天你均可以得到关于性能的热门广告,或者你更愿意本身动手对性能作些小改动而不是看 Netflix。

致谢

谢谢 Malte Ubl 撰写这篇文章。这个网站自己最初是由过于有才华的 Lukasz Klis 开发,而使人称赞的设计则是由超酷的 Silke Voigts 为咱们带来,谢谢他们。

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区kuai链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索