樣式9:構建時間CSS-In-JS
Facebook去年四月發布了其重大改版。這是一個雄心勃勃的項目,是對一個擁有海量用戶的龐大網站的重建。為了實現這一目標,他們使用了自己創建並開源的幾項技術,例如React、GraphQL、Relay和一個名為stylex的新CSS-in-JS庫。
這個新庫是Facebook內部使用的,但他們分享了足夠的信息,使得開源實現style9成為可能。
為什麼需要另一個CIJ庫?
現已存在大量的CSS-in-JS (CIJ)庫,因此可能不清楚為什麼還需要另一個庫。正如Christopher Chedeau所闡述的那樣,style9具有與所有其他CIJ解決方案相同的好處,包括作用域選擇器、死代碼消除、確定性解析以及在CSS和JavaScript之間共享值的能力。
然而,有一些方面使style9獨樹一幟。
最小的運行時
儘管樣式是在JavaScript中定義的,但它們由編譯器提取到常規的CSS文件中。這意味著最終的JavaScript文件中不會包含任何樣式。唯一剩下的就是最終的類名,最小的運行時將有條件地應用這些類名,就像您通常所做的那樣。這將導致代碼包更小、內存使用減少以及渲染速度更快。
由於值是在編譯時提取的,因此無法使用真正動態的值。幸運的是,這些值並不常見,而且由於它們是唯一的,因此不會因為內聯定義而受到影響。更常見的是有條件地應用樣式,當然這是支持的。多虧了babel的path.evaluate,局部常量和數學表達式也是支持的。
原子輸出
由於style9的工作方式,每個屬性聲明都可以成為具有單個屬性的獨立類。例如,如果我們在代碼中多個地方使用opacity: 0,它在生成的CSS中只會存在一次。這樣做的好處是,CSS文件的大小隨著唯一聲明的數量而增長,而不是隨著聲明的總數而增長。由於大多數屬性被多次使用,這可以導致CSS文件大幅縮小。例如,Facebook舊的首頁使用了413 KB的gzip壓縮CSS。改版後,所有頁面的CSS大小為74 KB。同樣,較小的文件大小會導致更好的性能。
有些人可能會抱怨這一點,認為生成的類名不是語義化的,它們是不透明的,並且忽略了級聯。這是真的。我們將CSS視為編譯目標。但這是有充分理由的。通過質疑以前被認為最佳的實踐,我們可以改善用戶和開發人員的體驗。
此外,style9還有許多其他強大的功能,包括:使用TypeScript進行類型化樣式、消除未使用樣式、使用JavaScript變量的能力以及對媒體查詢、偽選擇器和關鍵幀的支持。
如何使用它
首先,像往常一樣安裝它:
<code>npm install style9</code>
style9有針對Rollup、Webpack、Gatsby和Next.js的插件,它們都基於Babel插件。關於如何使用它們的說明可在存儲庫中找到。在這裡,我們將使用webpack插件。
<code>const Style9Plugin = require('style9/webpack'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { module: { rules: [ // 这将转换style9调用{ test: /\.(tsx|ts|js|mjs|jsx)$/, use: Style9Plugin.loader }, // 这是正常的Webpack CSS提取的一部分{ test: /\.css$/i, use: [MiniCssExtractPlugin.loader, 'css-loader'] } ] }, plugins: [ // 这将对最终的CSS文件中的声明进行排序并删除重复的声明new Style9Plugin(), // 这是正常的Webpack CSS提取的一部分new MiniCssExtractPlugin() ] };</code>
定義樣式
創建樣式的語法與其他庫非常相似。我們首先使用樣式對象調用style9.create:
<code>import style9 from 'style9'; const styles = style9.create({ button: { padding: 0, color: 'rebeccapurple' }, padding: { padding: 12 }, icon: { width: 24, height: 24 } });</code>
因為所有聲明都將產生原子類,所以諸如flex: 1和background: blue之類的簡寫將不起作用,因為它們設置了多個屬性。可以展開的屬性,例如padding、margin、overflow等,將自動轉換為它們的完整形式。如果您使用TypeScript,則在使用不受支持的屬性時會收到錯誤。
解析樣式
要生成類名,我們現在可以調用style9.create返回的函數。它接受我們要使用的樣式鍵作為參數:
<code>const className = styles('button');</code>
該函數的工作方式是這樣的:右側的樣式優先,並將與左側的樣式合併,就像Object.assign一樣。以下將產生一個填充為12px且文本為rebeccapurple的元素。
<code>const className = styles('button', 'padding');</code>
我們可以使用以下任何格式有條件地應用樣式:
<code>// 逻辑与styles('button', hasPadding && 'padding'); // 三元运算符styles('button', isGreen ? 'green' : 'red'); // 布尔对象styles({ button: true, green: isGreen, padding: hasPadding });</code>
這些函數調用將在編譯期間被刪除,並替換為直接的字符串連接。上面代碼中的第一行將被替換為類似'c1r9f2e5 ' hasPadding ? 'cu2kwdz ' : ''的內容。沒有留下運行時代碼。
組合樣式
我們可以通過使用屬性名訪問樣式對象並將其傳遞給style9來擴展樣式對象。
<code>const styles = style9.create({ blue: { color: 'blue; } }); const otherStyles = style9.create({ red: { color: 'red; } }); // 将为红色const className = style9(styles.blue, otherStyles.red);</code>
就像函數調用一樣,右側的樣式優先。但是,在這種情況下,類名不能靜態解析。相反,屬性值將被類替換,並在運行時連接。屬性像以前一樣添加到CSS文件中。
總結
CSS-in-JS 的好處是真實存在的。也就是說,當我們將樣式嵌入到代碼中時,會產生性能成本。通過在構建時提取值,我們可以同時獲得兩全其美的效果。我們可以從將樣式與標記放在一起以及使用現有的JavaScript基礎設施中獲益,同時還可以生成最佳樣式表。
如果style9聽起來很有趣,請查看存儲庫並試用一下。如果您有任何疑問,請隨時提出問題或聯繫我們。
致謝
感謝Giuseppe Gurgone 對style-sheet和dss的工作,感謝Nicolas Gallagher對react-native-web的工作,感謝Satyajit Sahoo和Callstack的全體成員對linaria的工作,感謝Christopher Chedeau、Sebastian McKenzie、Frank Yan、Ashley Watkins、Naman Goel以及在Facebook上從事stylex工作的其他所有人願意公開分享他們的經驗教訓。以及任何其他我錯過的其他人。
鏈接
- johanholmerin/style9
- 使用React、GraphQL和Relay構建新的facebook.com – 2019年4月30日
- 使用React和Relay構建新的Facebook | Frank Yan – 2019年10月30日
- 新的Facebook.com的技術棧重建– 2020年5月8日
- johanholmerin/style9-components.macro:style9的Styled Components API – 實驗性
以上是樣式9:構建時間CSS-In-JS的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)