跳到内容
返回博客

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 Server Components 和 Next.js App Router 的时代,像 Material UI 这样的组件库有机会通过将渲染工作从客户端转移到服务器来获得性能提升。

问题是,我们依赖的“传统” CSS-in-JS 解决方案无法与我们同行,因为 React context API 仅适用于客户端组件。在 State of CSS 2023 调查 中,近 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 在 2022 年底推出 App Router,首次实现 React Server Components 规范之后,很明显地看到地平线上出现了一个巨大的转变。

RSC 为 React 解锁了一个全新的可能性领域;对于我们作为 UI 开发者而言,这意味着我们可以创建完全在构建时可渲染的组件,因此我们不必在运行时将该负担传递给客户端。但是,使用 RSC 需要我们放弃熟悉的 API,例如 React.useContext,这反过来又成为使用上一代样式引擎(如 Emotion)的主要障碍,因为它们严重依赖此钩子来实现主题化。

Material UI 是一个独特的用例

Material UI 每月被下载数百万次,并且是互联网上经过最严格实战测试的 UI 库之一,其 GitHub 历史可以追溯到 2014 年。它必须进行一些重大更改才能跟上时代;最近,从 v4 到 v5 从 JSS 迁移到 Emotion。虽然这些破坏性更改总体上带来了许多好处,但不幸的是,它们也带来了痛苦的迁移体验。

我们吸取了教训!我们不想再次将此强加给您。

因此,当需要寻找一种新的样式生成方式时,我们知道我们需要使语法和创作体验尽可能地类似于 Emotion 和 styled-components,并为大多数破坏性更改提供代码模组,以最大程度地减少迁移时的摩擦。

其他选项不符合我们的需求

对于我们这些对 CSS-in-JS 中已知和喜爱的模式感到非常满意的人来说,仅仅为了再次重新发明轮子而考虑放弃所有这些肌肉记忆会感到沮丧。我们喜欢并置样式的 DX,并且我们宁愿不将 API 迁移到原子类名。我们希望大规模支持嵌套选择器——因此 Tailwind CSS、StyleX、Panda CSS 以及最近几个月出现的其他解决方案不是可行的选择。

Pigment CSS 最初是 Linaria 的一个分支,但我们发现使用 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 为我们提供了第一次 glimpse;RedwoodJS 最近发布了他们自己的实现;许多其他框架和元框架(如 Remix)目前正在制定 POC 和 RFC 以赶上步伐。无论 Server Components 在开发者中普及的速度有多快,很明显,库维护者现在必须支持 the two Reacts(客户端和服务器端)才能在未来保持相关性。

因此,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。当您在那里时,为什么不 ⭐️ star 存储库 ⭐️ 让我们知道您很兴奋,并帮助向其他人传播这个消息呢? 😁