[譯] styled-components v3.1.0

旭霸發表於2019-02-27

原文連結:https://medium.com/styled-components/v3-1-0-such-perf-wow-many-streams-c45c434dbd03

image

V3.1.0: 帶來巨大的效能提升和流式伺服器端渲染支援

一種新的 CSS 注入機制意味著在生產環境中更快的客戶端渲染,同時流式伺服器端渲染使得首位元組時間(TTFB)更快。

在生產環境中更快捷的CSS注入

CSS注入早就不是什麼新鮮事了。早在一年半以前,Sunil Pai就發現了一個鮮為人知的DOM API: insertRule。它使我們能用JS的方式把CSS快速注入到DOM當中。唯一的缺點是這些樣式不能在瀏覽器的開發者工具中編輯。

當 Glen 和 Max 第一次寫出styled-components的時候,他們完全是從開發者的體驗出發的。對於小型應用來說效能問題還不明顯,所以他們決定不再使用insertRule。但是當越來越多的人開始使用,並且使用在大型應用程式中時,樣式注入就成了瓶頸,特別對於一些高度動態的案例來說。

多虧了 Reddit 的前端工程師 Ryan Schwers,styled-components 3.1.0版本在生產環境中預設使用insertRule

我們將該版本與之前的版本(3.0.2)做了些對比,結果遠超預期:

image

Mount的時間減少了將近10倍,而重新渲染的時間減少了將近20倍!

注意,這樣的比較是基於壓力測試,不一定適用於真實應用。可能你的應用渲染速度不一定能提升10倍,但是在我們的一個應用中,首次渲染時間減少了好幾百毫秒。

下圖是styled-components與其它一些主流的React CSS-in-JS框架的比較(淡紅色是3.0.2版本,深紅色是3.1.0版本):

image

儘管目前styled-components還不是最快的,但比最快的也慢不了多少,至少之前的瓶頸也已經不復存在了。這樣的結果實在是鼓舞人心,我們也非常希望得到各位使用者的反饋。

流式伺服器端渲染

流式伺服器端渲染的概念實在React V16中引進的。它允許React還在渲染的時候,服務端仍然能傳送HTML,這使得首位元組時間更快,並且Node伺服器能更容易的處理背壓(Back-pressure)。

這與 CSS-in-JS 不太搭:
通常,我們在React完成渲染後,將所有元件的樣式放在<style>標籤中,然後插入到<head>裡面。而在流式情況下,在任何元件都沒被渲染的時候,<head>已經傳送給使用者了,這時候我們就無法插入任何東西了。

解決方案就是在渲染元件的時候,把HTML和樣式混在一起,而不是等到最後,一次性的插入所有的元件。但是這樣會使HTML和style標籤都糅雜在一起,所以我們最後還是要在重注入(rehydration)之前把所有的style都合併到head裡面。

我們已經實現了這一點,你現在可以同時使用流式伺服器端渲染和styled-components。就像這樣:

import { renderToNodeStream } from `react-dom/server`
import styled, { ServerStyleSheet } from `styled-components`
res.write(`<!DOCTYPE html><html><head><title>My Title</title></head><body><div id="root">`)
const sheet = new ServerStyleSheet()
const jsx = sheet.collectStyles(<App />)
// Interleave the HTML stream with <style> tags
const stream = sheet.interleaveWithNodeStream(
  renderToNodeStream(jsx)
)
stream.pipe(res, { end: false })
stream.on(`end`, () => res.end(`</div></body></html>`))
複製程式碼

然後在客戶端,我們必須呼叫consolidateStreamedStyles()API來為React的重注入(rehydration)做準備:

import ReactDOM from `react-dom`
import { consolidateStreamedStyles } from `styled-components`
/* Make sure you call this before ReactDOM.hydrate! */
consolidateStreamedStyles()
ReactDOM.hydrate(<App />, rootElem)
複製程式碼

好訊息!

如果你使用的是v2或者甚至v1,不用擔心,新版本完全是向後相容的。並且你也可以無縫的升級至新版本。新版本中有很多的更新,希望你和你的使用者能夠喜歡。

相關文章