样式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)

关于Flex布局中紫色斜线区域的疑问在使用Flex布局时,你可能会遇到一些令人困惑的现象,比如在开发者工具(d...
