[譯] 構建世界上最快的會議網站

這是 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鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索