像 google 一样通过缩短 css 类名和作用域隔离来压缩优化 css 包的大小
就像 google 的做法一样
今年年初,我已经退出咨询公司并开始构建 GO2CINEMA - 一个 快速,简单和安全 的方式来预订英国的电影票的网站。我做了一个辉煌的工作,使其快速,简单和安全。在其中某个阶段,我一直痴迷于关键渲染路径的优化。⚡️
我已经使用 ūsus 解决了 HTML 的预渲染。ūsus 渲染单页应用程序(SPA)的 HTML,并内嵌了用于呈现页面的 CSS。但是,我并不喜欢在每个 HTML 文档内嵌 70 KB 的 css,特别是其中大部分是 CSS 类名。
就像Google一样
你有没有看过 https://www.google.com/ 的源代码?如果看过,您注意到的第一件事是会是,CSS 类名称没有超过几个字符。
但是怎么样做到的呢?
CSS minifiers 的缺点
有一件事,minifier
不能做 - 改变选择器名称。这是因为 CSS minifier
不能控制 HTML 输出。同时,CSS 名称可以很长。
如果您使用 CSS modules
,您的 CSS modules 可能会包含样式表文件名,本地标识名和随机哈希。使用 css-loader localIdentName 配置描述类名模板,例如[name]___[local]___[hash:base64:5]
。因此,生成的类名称将如下所示 .MovieView___movie-title___yvKVV
; 如果你喜欢描述性的名字,它可能更长,例如 .MovieView___movie-description-with-summary-paragraph___yvKVV
。
在编译时重命名 CSS 类名
但是,如果您使用的是 webpack
和 babel-plugin-react-css-modules
,那么您很幸运 🍀 - 您可以使用 css-loader
的 getLocalIdent
配置项或者等效的 babel-plugin-react-css-modules
中的 generateScopedName
配置项来达到在编译时重命名类名的目的。
generateScopedName
中很酷的是,同样的功能实例可以用于 Babel
和 webpack
的构建过程:
让名字变短
感谢 babel-plugin-react-css-modules
和 css-loader
共享相同的逻辑来生成 CSS 类名称,我们可以将类名改为任何我们喜欢的,甚至是随机哈希。然而,我想要最短的类名,而不是随机哈希。
为了生成最短的类名,我创建了类名索引,并使用该 incstr
模块为索引中的每个条目生成增量ID。
这保证了类名简短并且唯一。现在,.MovieView___movie-title___yvKVV
和 .MovieView___movie-description-with-summary-paragraph___yvKVV
的类名都成了 .a_a
, .b_a
等。
这将 GO2CINEMA
CSS 压缩包的大小从 140 KB 降低到 53KB。
使用作用域隔离来进一步减少包的大小
分离组件名称和本地标识符名称是一个很好的理由让我添加 _
到 CSS 类名 - 对于缩小文件大小特别有用。
csso(CSS minifier)具有作用域配置。作用域定义了在某些标记上专门使用的类名列表,即来自不同作用域的选择器不会匹配同一个元素。这一条让优化规则更进一步。
要利用此功能,请使用 csso-webpack-plugin
来后处理 CSS 包:
这使 GO2CINEMA CSS 捆绑包的大小从 53 KB 降至 47 KB。
这值得么?
这种压缩的第一个争议是觉得压缩算法本来就可以做到。使用 Brotli 算法压缩的 GO2CINEMA CSS 包与长类名的原始包相比只压缩了 1 KB。
另一方面,设置这个缩小是一次性投入,它减少了需要解析的文档的大小。它还具有其他好处,例如阻止依赖 CSS类名称的扫描仪导航或意外匹配广告拦截器黑名单的 CSS选择器。
同时,您可以看到在 GO2CINEMA 和 venue 页面上使用的这种压缩的演示,例如