GitHub 如何通过迁移 CSS Modules 将 SSR 时间降低 55%
Improving site performance by shipping more CSS
GitHub 工程师 Josh Black 复盘将 Primer 设计系统从 CSS-in-JS 迁移到 CSS Modules 的历程。截至 2024 年 12 月 Primer 全部组件迁移完成,服务端渲染时间减少 55%,组件初始化时间减少 25%。
原文给出大厂从 CSS-in-JS 迁移到 CSS Modules 的完整路径和量化收益,可迁移到类似的前端架构改造。
Primer 设计系统为你在 GitHub 上看到的许多体验提供支持。从按钮到横幅再到面包屑,这些基础组件需要在各种场景下都具备可访问性、灵活性和高性能。
早在 2023 年,某些页面上的组件数量开始激增。这给我们现有的 CSS-in-JS 方案带来了若干与性能相关的挑战:
- 由于样式在客户端初始化,初始页面加载耗时更长
- 随着样式收集从客户端转移,服务端渲染性能下降
- 随着页面上组件数量的增长,样式更新变得失控
很明显,Primer 团队需要从根源上解决这个问题。我们需要找到一种替代方案,彻底避免当前方案中出现的客户端和服务端开销。最重要的是,我们选择的任何替代方案都必须以在迁移过程中不会对 GitHub 造成任何破坏的方式运作。
引入 CSS(Modules)
Primer 团队找到了一个满足我们所有标准的方案:CSS Modules。这种格式让我们能够做我们最喜欢的事情之一:编写和使用原生 CSS 特性,同时仍然保留我们从 CSS-in-JS 中习以为常的某种程度的同置和封装。
使用 CSS Modules,样式将与组件的 JavaScript 源码一起编写在 CSS 文件中。它还允许我们默认将所有类名视为局部作用域,从而避免全局选择器可能带来的一些冲突和挑战。这种格式还消除了对任何客户端或服务端运行时行为的需求。相反,样式会汇总到 CSS 样式表中,作为页面 HTML 的一部分发送。
然而,这个方案与当时我们使用的 CSS-in-JS 方案截然不同。这一变更需要更新每一个 Primer 组件,以及 GitHub 上每一个使用该技术编写的组件。所幸,设计系统是规模化交付这类变更的完美载体。
逐步迈向 CSS Modules
转向 CSS Modules 的形势很明确。Primer 团队需要为其每个组件交付更新,将它们从 CSS-in-JS 迁移到 CSS Modules。与此同时,我们对这些组件所做的更新不能破坏 GitHub 中的任何使用。最后,我们用于 CSS-in-JS 的底层技术也必须继续为 GitHub 中当前正在使用它的任何组件正常工作。
在这些约束条件下,我们决定采用增量迁移策略,使我们能够安全地发布组件更新而不破坏整个系统。对于每个组件,我们的计划是:
- 添加一个新文件,将现有样式转换为 CSS Modules
- 将该组件加入一个功能开关,在新旧样式之间切换
- 使用现有的视觉回归测试来验证 CSS-in-JS 方案与 CSS Modules 之间的快照完全一致
- 逐步向我们的团队、然后是 GitHub 员工、最后是所有 GitHub 用户推出该功能开关,以便在此过程中捕获任何问题
这一过程形成了一个强大的反馈循环,随着 Primer 持续向 GitHub 交付这些变更,问题在流程早期就被标记出来。功能开关的使用使我们能够安全地进行这次迁移,同时为我们提供了关于 CSS Modules 性能收益的清晰信号。
到 2024 年 12 月,Primer 中的所有组件都已通过这一流程迁移到 CSS Modules。我们在各方面都看到了性能提升,尤其是:
- 服务端渲染页面的时间减少了 55%
- 页面上组件初始化所需时间减少了 25%
由于在 Primer 中开展这项工作带来了明显的性能提升,我们开始思考,如果在 GitHub 的其他部分也进行这些转换,是否也能看到类似的性能提升。同样,我们还需要多久才能最终在整个公司范围内放弃对 CSS-in-JS 的支持?
在 GitHub 中摆脱 CSS-in-JS
从 Primer 中移除我们的 CSS-in-JS 解决方案最棘手的部分之一,是因为 sx prop 的使用。这个 prop 曾是样式化和自定义 Primer 组件的唯一方式。团队可以提供一个内联对象来自定义组件的一切。它代表了 CSS-in-JS 最好和最坏的两面:
- 出色的 TypeScript 支持,并与我们的 Design Tokens 集成
- 与组件共置一处,因此所有内容都在同一个地方
- 由于用于
sx的内联对象具有动态特性,运行时成本很高 - 随着页面上使用
sx的组件数量增长,扩展变得困难
因此,我们摆脱 CSS-in-JS 之旅的第一步,是减少 GitHub 中 sx 的使用。这将使我们能够立即获得与迁移 Primer 组件时类似的性能提升。它也为我们从产品中彻底移除 CSS-in-JS 做好了完美铺垫。
Primer 的双重性
需要注意的是,虽然设计系统本身已正式脱离 styled-components,但 GitHub 代码库本身有很大一部分并没有。由于多年来 sx props 一直是 GitHub 事实上的样式标准,我们面对的是成千上万个需要迁移的 sx props,然后才能考虑将 GitHub 迁移到不依赖 styled-components 的、简洁的新版 @primer/react。
那么……我们是如何在完成如此大量工作的同时提高信心并降低风险的呢?答案是:并非一次性完成。
最初的 CSS 迁移比我们透露的要更细致一些:除了将组件迁移到 CSS modules、通过功能标志在生产环境中测试并逐步推出之外,我们还创建了一个传递性库中的“包装器”组件,我们称之为 @primer/styled-react。这个包的全部目的,是允许在新迁移的组件中使用 sx。这样,GitHub UI 代码库中使用这个 prop 的实例,就可以通过从 @primer/styled-react 导入同一个组件来继续使用它们,同时对于不使用它的场景,我们则实现了直接从 @primer/react 导入所带来的性能收益。
Styled Box Zero
迁移过程的下一阶段如下:
- On a package-by-package basis:
- 将所有
sx用法转换为等效的 CSS modules 文件。这包括交叉引用(参见迁移到 CSS variables) - 将
@primer/styled-react导入替换为@primer/react导入 - 在预生产环境中测试
- 部署
- 将所有
说来也巧,就在我们准备着手这项浩大工程时,styled-components 宣布进入维护模式,这进一步印证了我们正朝着正确的方向迈进。
这项工作于 2025 年 4 月启动,待迁移的 sx props 峰值约为 7,760 个;直到 2026 年 5 月我们才看到它真正落地。最初,我们内部一位出色的开发者 Ian Sanders 创建了一个 VS Code 插件,用于辅助逐个 prop 的迁移。我们还在内部开发了一个类似的 codemod,用于迁移 GitHub 代码库中的整个文件。这项工作虽然需要一些人工监督和仔细验证,但大部分是自动化的。由 8 名工程师轮番上阵,在 6 个月的时间里迁移了 6,419 个 props,并观察到服务端渲染时间性能提升,部分页面从 1% 到 22% 不等。

在 GitHub 的另一边,Copilot 的能力正呈指数级增长。AI 变得越来越聪明、越来越强大;在这项工作仍在进行时,我们发布了 Copilot coding agent 和 Copilot code review。
等到我们重新拾起这项工作时,已经是 2026 年 4 月,情况已大不相同;我们仅用两名工程师、坚定的决心以及大量 Copilot coding agents,就在三周内将 sx props 从 895 个降到了 0 个。

主题之战
那是个大日子:我们终于完成了横亘在我们与彻底移除 styled-components 之间的 sx 迁移,这历经数年……我们终于可以清理这些依赖,转向其他更令人兴奋的工作了,对吧?错!
GitHub 支持七种不同的主题,它们都提供高对比度模式变体。而这一切的实现,你猜对了,靠的就是 styled-components。在我们考虑移除这些依赖之前,必须先解耦我们的主题系统。
其实这并没有听起来那么严重。我们的主题变量一直通过 @primer/css 包在 CSS 中定义,而且在 2025 年底迁移 @primer/react 时,我们就已经为非 styled 主题做好了规划。我们需要移除的是由 styled-components 启用的 JavaScript 用法和工具函数。于是,我们再次投入工作。
到现在你应该熟悉套路了:执行迁移,缓慢推出,为一切加上功能开关。两个月后,期间经历了一些小波折,我们已全系统就绪,可以移除依赖了;我们甚至为此也加了功能开关。小心驶得万年船。
结局圆满
截至 2026 年 6 月,GitHub 已 100% 运行在 CSS modules 上。我们设置的各项保障措施使我们能够安全地推出重大架构变更,在生产环境中进行压力测试,捕获错误,高效地调整和修复,最终让我们成功实现目标,并在此过程中获得了显著的性能提升。
起初看似一次 CSS 迁移,最终却演变为对 GitHub 如何大规模设计样式、主题和发布 UI 的一次渐进式平台重构。最终,我们不仅从 dotcom 中移除了 sx、styled-components 和 styled-system,还在整个过程中没有破坏 GitHub。提升产品的性能、用户体验和愉悦感,始终是 GitHub 全体同仁的首要关注。
文章 Improving site performance by shipping more CSS 首次发表于 The GitHub Blog。
来源:GitHub Blog · github.blog