Sam Magura是 Spot 的软件工程师,也是活跃的Emotion库维护者。最近,他详细解释了 Spot 公司为什么放弃运行时 CSS-in-JS 库 Emotion,而选择了Sass模块——运行时开销、负载开销和服务器端渲染问题导致了较差的用户体验。
在他的博文中,Magura 首先回顾了运行时 CSS-in-JS 的好处。
今天的 Web 应用程序通常实现为一组协作的组件。在使用运行时 CSS-in-JS 库时,开发人员定义组件的样式以及组件标记和逻辑。如果以不正确的方式修改或删除了组件样式,就很难修改或删除组件代码。这解决了大型应用程序中充斥着未被检测到的过时样式规则的问题。但这样的应用程序下载和执行都比较笨重,对用户体验有负面影响。
将 CSS 规则的作用域严格限定到相关的组件就很难会无意影响到其他组件的样式。如果没有组件作用域,CSS 的级联和专一性规则可能会导致不相关组件的样式定义发生渗透。
最后,使用完备的图灵语言,如 JavaScript,开发人员可以完全自由地表达组件样式和组件逻辑之间的关系。如果组件样式不是静态的,并且需要根据用户操作或应用程序环境中的变更进行动态更新时,这样就很方便了。
不过,Magura 根据他对 Spot 代码库的研究得出结论,CSS-in-JS 的坏处大于好处:
所以,这就是我们放弃 CSS-in-JS 的原因——运行时性能成本太高了。
CSS-in-JS 可能会因其运行时和负载开销而对用户体验产生负面的影响。
一方面,在渲染时动态计算和更新样式可能会导致渲染变慢。Magura 比较了 Spot 用运行时 CSS-in-JS 库 Emotion 实现的代码库组件的渲染时间与用 Sass 模块实现的代码库组件的渲染时间(在构建时编译为普通的 CSS 文件)。对比显示,使用 Emotion 库的渲染时间几乎翻倍(27.7 毫秒对 54 毫秒)。开发人员可以从这篇博文中查看实验数据、火焰图分析等等。
另一方面,将 CSS-in-JS 库添加到应用程序代码中会加大浏览器下载的代码包,可能会降低应用程序的启动速度。Emotion 大约 8 KB(最小化后),而style-components,一个流行的 CSS-in-JS 库,是 12 KB。
有趣的是,运行时 CSS-in-JS 库执行的动态插入 CSS 样式规则可能并不总是与生态系统的其他部分很好地配合。
关于 React 18,Sebastian Markage在 GitHub Issues 中向使用 React 并发渲染功能的开发人员提出了如下的警告:
这是一个 CSS 库(动态生成新规则并将它们与<style>标签插入到文档中)的升级指南,特别是目前大多数专门为 React 设计的 CSS-in-JS 库,如 styled-components、styled-jsx、react-native-web。 注意:请务必阅读“When to Insert <style> on The Client”部分。如果你现在在“渲染期间”注入样式规则,会导致你的库在并发渲染时非常慢。
运行时 CSS-in-JS 也可能影响服务器端渲染优化。在一篇关于服务器端流的文章中,Misko Hevery(Qwik框架的作者)、Taylor Hunt和 Ryan Carato写道:
例如,CSS-in-JS(如 Emotion)是一种非常流行的方法。但是,如果这种方法意味着在输出样式标签之前所有组件都需要完全渲染,就会中断流,因为框架被迫缓冲整个响应。
Magura 提到,Emotion 的 GitHub 项目中记录的相当多的问题都与服务器端渲染有关(例如 React 18 的流、规则插入顺序)。报告的问题可能会产生显著的意外复杂性(即与解决方案相关的复杂性,而不是源于问题本身)。它们还可能导致负面的开发者体验。
虽然 Magura 提醒读者,他的实验仅限于 Emotion 库和 Spot 的代码库,但他预计大部分推理可能同样适用于其他运行时 CSS-in-JS 库和其他代码库。
一年前,Tomas Pustelnik提供了另一个数据点,尽管表述的方式不同,但指向的问题是相似的。Pustelnik 在他的博文“真实世界的CSS与CSS-in-JS的性能比较”中总结道:
就是这样。如你所见,运行时 CSS-in-JS 可以对网页产生明显的影响,主要针对低端设备和网络连接较慢或流量价格较高的地区。因此,也许我们应该更好地考虑使用什么工具以及如何使用工具。好的开发者体验不应该以牺牲用户体验为代价。 我认为我们(开发人员)应该更多地考虑我们为项目所选择的工具可能带来哪些影响。如果下一次我开始一个新项目,我将不再使用运行时 CSS-in-JS。我要么使用普通的 CSS,要么使用一些构建时 CSS-in-JS 替代方案。
流行的构建时 CSS-in-JS 库包括Linaria、Astroturf和vanilla-extract。去年,Facebook 推出了自己的构建时 CSS-in-JS 库stylex,开发人员仍然可以使用CSS模块和相关的生态系统(PostCSS模块、Sass模块)。
CSS-in-JS 指的是通过 JavaScript 生成 CSS 规则,而不是在外部 CSS 文件中定义样式。运行时 CSS-in-JS 库,如Emotion或styles-component,在运行时动态修改样式,例如将样式标签注入文档。零运行时 CSS-in-JS 是一种在构建时提取所有 CSS 的模式。
查看英文原文:https://www.infoq.com/news/2022/10/prefer-build-time-css-js/
领取专属 10元无门槛券
私享最新 技术干货