原文鏈接:https://medium.com/styled-components/v3-1-0-such-perf-wow-many-streams-c45c434dbd03
V3.1.0: 帶來巨大的性能提升和流式服務(wù)器端渲染支持
一種新的 CSS 注入機制意味著在生產(chǎn)環(huán)境中更快的客戶端渲染,同時流式服務(wù)器端渲染使得首字節(jié)時間(TTFB)更快。
在生產(chǎn)環(huán)境中更快捷的CSS注入
CSS注入早就不是什么新鮮事了。早在一年半以前,Sunil Pai就發(fā)現(xiàn)了一個鮮為人知的DOM API: insertRule。它使我們能用JS的方式把CSS快速注入到DOM當中。唯一的缺點是這些樣式不能在瀏覽器的開發(fā)者工具中編輯。
當 Glen 和 Max 第一次寫出styled-components的時候,他們完全是從開發(fā)者的體驗出發(fā)的。對于小型應(yīng)用來說性能問題還不明顯,所以他們決定不再使用insertRule。但是當越來越多的人開始使用,并且使用在大型應(yīng)用程序中時,樣式注入就成了瓶頸,特別對于一些高度動態(tài)的案例來說。
多虧了 Reddit 的前端工程師 Ryan Schwers,styled-components 3.1.0版本在生產(chǎn)環(huán)境中默認使用insertRule。
我們將該版本與之前的版本(3.0.2)做了些對比,結(jié)果遠超預(yù)期:
Mount的時間減少了將近10倍,而重新渲染的時間減少了將近20倍!
注意,這樣的比較是基于壓力測試,不一定適用于真實應(yīng)用??赡苣愕膽?yīng)用渲染速度不一定能提升10倍,但是在我們的一個應(yīng)用中,首次渲染時間減少了好幾百毫秒。
下圖是styled-components與其它一些主流的React CSS-in-JS框架的比較(淡紅色是3.0.2版本,深紅色是3.1.0版本):
盡管目前styled-components還不是最快的,但比最快的也慢不了多少,至少之前的瓶頸也已經(jīng)不復(fù)存在了。這樣的結(jié)果實在是鼓舞人心,我們也非常希望得到各位用戶的反饋。
流式服務(wù)器端渲染
流式服務(wù)器端渲染的概念實在React V16中引進的。它允許React還在渲染的時候,服務(wù)端仍然能發(fā)送HTML,這使得首字節(jié)時間更快,并且Node服務(wù)器能更容易的處理背壓(Back-pressure)。
這與 CSS-in-JS 不太搭:
通常,我們在React完成渲染后,將所有組件的樣式放在<style>標簽中,然后插入到<head>里面。而在流式情況下,在任何組件都沒被渲染的時候,<head>已經(jīng)發(fā)送給用戶了,這時候我們就無法插入任何東西了。
解決方案就是在渲染組件的時候,把HTML和樣式混在一起,而不是等到最后,一次性的插入所有的組件。但是這樣會使HTML和style標簽都糅雜在一起,所以我們最后還是要在重注入(rehydration)之前把所有的style都合并到head里面。
我們已經(jīng)實現(xiàn)了這一點,你現(xiàn)在可以同時使用流式服務(wù)器端渲染和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>'))
然后在客戶端,我們必須調(diào)用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,不用擔心,新版本完全是向后兼容的。并且你也可以無縫的升級至新版本。新版本中有很多的更新,希望你和你的用戶能夠喜歡。