跳至內容
返回部落格

Pigment CSS 預覽:新一代 CSS-in-JS

Sam Sycamore

@samuelsycamore

Brijesh Bittu

@brijeshb42

Siriwat Kunaporn

@siriwatknp

Marija Najdova

@mnajdova

Danilo Leal

@danilo-leal

Olivier Tassinari

@oliviertassinari
+

觀看 MUI 的 CEO Olivier Tassinari 在 React Conf 2024 上介紹 Pigment CSS

在 React 伺服器組件和 Next.js App Router 的時代,像 Material UI 這樣的組件庫有機會透過將渲染工作從客戶端移至伺服器來提升效能。

問題是,我們仰賴的「傳統」CSS-in-JS 解決方案無法與我們一同前進,因為 React context API 僅適用於客戶端組件。在 2023 年 CSS 現狀調查 中,將近 70% 的受訪者表示他們使用 styled-components 和 Emotion,我們看到大量的 React 開發人員在此處沒有明確的前進方向。

對於像 Material UI 這樣廣泛使用的庫來說,最大的挑戰是在創新同時盡可能減少重大變更。我們需要維持一致且可靠的開發人員體驗,而無需您完全改變建置 UI 組件的方式。

這就是 Pigment CSS 的用武之地。

Introducing Pigment CSS: the next generation of CSS-in-JS

Pigment CSS 是一個零執行階段 CSS-in-JS 庫,可在建置時將共置樣式產生到它們自己的 CSS 檔案中。與 Material UI v5 中使用的樣式引擎 Emotion 相比,使用 Pigment CSS 您可以獲得顯著的效能提升,加上 RSC 相容性。儘管我們在早期開發中優先考慮 Material UI 使用者的需求,並專注於平穩的遷移,但 Pigment CSS 可以與您偏好的任何 React 組件庫一起使用。

為何選擇 Pigment CSS?

傳統 CSS-in-JS 已不足夠

Emotion 對於 2021 年末的 Material UI v5.0.0 來說非常有意義,但自那時以來,React 生態系統發生了巨大變化。在 Next.js 透過 App Router 於 2022 年底首次實作 React 伺服器組件規範後,很明顯地,地平線上出現了巨大的轉變。

RSC 為 React 開啟了全新的可能性領域;對於我們作為 UI 開發人員來說,這意味著我們可以建立完全可在建置時渲染的組件,因此我們不必在執行階段將該負擔轉嫁給客戶端。但是使用 RSC 需要我們放棄熟悉的 API,例如 React.useContext,這反過來成為使用像 Emotion 這樣的上一代樣式引擎的主要障礙,因為它們嚴重依賴此 Hook 進行主題設定。

Material UI 是一個獨特的使用案例

Material UI 每月下載數百萬次,並且是網際網路上經過最嚴格實戰測試的 UI 庫之一,其 GitHub 歷史可以追溯到 2014 年。為了跟上時代的步伐,它不得不進行一些重大變更;最近一次是從 v4 到 v5 從 JSS 遷移到 Emotion。雖然這些重大變更確實帶來了許多整體優勢,但不幸的是,它們也帶來了痛苦的遷移體驗。

我們記取了教訓!我們不想再次將此強加於您。

因此,當要尋找產生樣式的新方法時,我們知道我們需要盡可能保持語法和撰寫體驗與 Emotion 和 styled-components 相似—並為大多數重大變更提供程式碼修改 (codemod)—以便在遷移時最大限度地減少摩擦。

其他選項不符合我們的需求

對於我們這些對 CSS-in-JS 中已知和喜愛的模式感到非常滿意的人來說,僅僅為了再次重新發明輪子而考慮放棄所有肌肉記憶,這讓人感到沮喪。我們喜歡共置樣式的 DX,並且我們寧願不將 API 遷移到原子類別名稱。我們希望大規模支援巢狀選取器—因此 Tailwind CSS、StyleX、Panda CSS 和最近幾個月出現的其他解決方案不是可行的選項。

Pigment CSS 最初是 Linaria 的分支,但我們發現更多我們需要的工具,可以透過 WyW-in-JS 來實現我們的目標,WyW-in-JS 是一個也為 Linaria 提供支援的開放原始碼庫。

Pigment CSS 的運作方式

Pigment CSS 是一個零執行階段 CSS-in-JS 庫:這表示它無法存取終端使用者的瀏覽器 JavaScript 執行階段,因此它無法使用執行階段來產生和插入 CSS。相反地,它會在建置時完成所有處理,以預先產生 CSS,然後 CSS 會成為輸出捆綁包的一部分。

它使用 WyW-in-JS 處理器功能,這使得建立自訂邏輯成為可能,該邏輯由來自庫的不同匯入的存在觸發。處理器在原始程式碼中尋找 styled()css() 和其他函式呼叫,並擷取要評估的引數。然後將這些值交還給 Pigment CSS 以進行額外的剖析和評估。

使用 Pigment CSS 的優點

對於 Emotion 和 styled-components 的使用者來說,採用 Pigment CSS 的優點是顯而易見的:您的終端使用者獲得更好的效能,並且您獲得 RSC 和 App Router 相容性,而無需大幅變更您撰寫組件樣式的方式。

更佳的頁面載入效能

當比較使用 Next.js 和 Emotion 或 Pigment CSS 建置的相同 Material UI 應用程式時,我們觀察到使用相同程式碼的以下頁面載入效能提升

指標 Emotion Pigment CSS 變更
首次載入 JS 131 kB 104 kB -20%
總封鎖時間 280 毫秒 210 毫秒 -25%

更佳的執行階段效能

當比較使用 Next.js 和 Emotion 或 Pigment CSS 建置的相同 Material UI 應用程式時,我們觀察到使用相同程式碼的以下執行階段效能提升

指標 Emotion Pigment CSS 變更
建立並掛載新按鈕 17.3 毫秒 10.1 毫秒 -42%
變更已掛載組件上的變體 14.0 毫秒 9.13 毫秒 -34%
變更 CSS 屬性內的值 13.6 毫秒 8.63 毫秒 -37%

熟悉的開發人員體驗

對於從 Emotion 或 styled-components 遷移的開發人員來說,您可能已經熟悉 Pigment CSS 採用的最常見模式。styled()css() 是用於定義樣式的兩個主要函式,它們的工作方式大致與您期望的相同(由於建置時 CSS-in-JS 的性質,存在一些顯著差異—請參閱 來自 Emotion 或 styled-components 以取得詳細資訊)。

import { styled, css } from '@pigment-css/react';

const Title = styled('h1') ({
  fontSize: '2rem';
});

const Container = styled.div`
  border: 1px solid red;

  &:hover {
    border-color: blue;
  }

  ${Title} {
    margin-bottom: 2.5rem;
  }
`;

export default function Modal() {
  return (
    <Container>
      <Title>Hello</Title>
      <p className={css({ color: 'pink' })}>World</p>
    </Container>
  );
}

我們也從 MUI System 移植了 sx 屬性,因此您仍然可以直接在給定的組件中定義樣式,但現在它的效能比以前更高。在 Pigment CSS 中,我們擴展了對 sx 的支援,使其包含所有 DOM 節點—而不僅僅是 Material UI 組件—因此您不需要使用 Box 組件包裝簡單的 <div><span> 來將主題樣式應用於它。

<section sx={{ p: 2, border: '1px solid', borderColor: 'divider' }}>
  <h1 sx={{ fontSize: '2rem', fontWeight: 700, mb: 1 }}>
    Introducing Pigment CSS: the next generation of CSS-in-JS
  </h1>
  <p sx={{ color: 'text.primary', fontWeight: 500 }}>
    Pigment CSS offers significant performance gains along with RSC
  </p>
</section>

面向未來的解決方案

儘管我們仍處於 RSC 時代的早期階段,但似乎隨著時間的推移,整個 React 生態系統將不可避免地朝著這種新範例趨同。Next.js 透過 App Router 為我們提供了初步了解;RedwoodJS 最近發布了他們自己的實作;許多其他框架和元框架(如 Remix)目前正在制定 POC 和 RFC 以趕上進度。無論伺服器組件在開發人員中普及的速度有多快,很明顯,庫維護人員現在必須支援 兩個 React(客戶端和伺服器端)才能在未來保持相關性。

因此,Pigment CSS 是 MUI 對 React 生態系統的長期性和永續性的另一個押注—以及我們承諾將在未來幾年繼續在這個領域進行創新。

或許最重要的是:由於 Pigment CSS 由 Material UI 背後的同一群人維護,因此我們將對該工具隨著時間推移的發展方式擁有更多的控制權,以繼續滿足使用者的需求。在理想的世界中,這將是您最後一次需要將 Material UI 應用程式遷移到新的樣式引擎。我們將盡力實現這一目標。🤞

下一步

Pigment CSS 目前處於早期 Alpha 開發階段—計畫是在今年稍後與 Material UI v6 一起發布功能完整的版本。屆時,您可以選擇在升級到 v6 後逐步選擇加入 Pigment CSS,讓您有充足的時間按照自己的步調進行遷移。

也就是說,Pigment CSS 現在可用於實驗,我們很樂意讓您試用並告訴我們您的想法—您在此階段的回饋可能會對最終產品產生重大影響。

開始使用 Pigment CSS

前往 Pigment CSS 儲存庫 了解如何設定並開始試用。如果您在過程中遇到任何錯誤或挫折,請隨時 開啟新的 issue。當您在那裡時,何不 ⭐️ 為儲存庫加星號 ⭐️ 讓我們知道您很興奮,並幫助向其他人傳播這個消息?😁