引言
团队很多项目,无论是vite还是webpack,写样式时都用了sass + postcss,然而随着项目越来越重,打包耗时也越来越长,ts和js代码可以使用swc等rust工具来编译,替换后确实提速效果是比较明显的,然而css打包也是影响整体打包速度的重要因素,而找了半天没发现太好的适合我们场景的css打包工具,所以决定自己写一个。
分析需求
首先我们90%的项目都用了postcss,依赖于一些postcss的插件,社区的lightningcss相当优秀,但是没法作为postcss插件使用,所以需要自己封装。
其实已经有大佬基于lightningcss提供Node版本的封装了postcss-lightningcss插件,但是遗憾的是该插件只有核心的编译功能是使用官方提供的用Rust开发封装过后的lightningcss模块,其他写 postcss 插件的逻辑还是使用js实现的,甚至还引入了node模块 browserslist来处理浏览器范围字符串的转化逻辑,所以性能上还是打了一些折扣的。这就让强迫症的我很是难受,要搞就搞个完美点的嘛。
@gogors/postcss-lightningcss-rs
那么 @
gogors/postcss-lightningcss-rs 即是从头到脚完全用Rust实现的postcss插件,包括浏览器范围字符串的转化逻辑也是用的Rust模块,例如你可以写[">= .25%", "chrome 90"]来描述兼容性,插件内部去帮你在处理具体文件前进行转化,只转化一次,而不是处理每个文件时都去转化一次。并将能缓存的地方缓存,只取我们需要的功能,相比于基于全量的node版本的lightningcss去封装,纯Rust版本的无论是逻辑还是体积都更轻量,但是功能上却是完全一致的。
最重要的是,该插件支持处理嵌套css语法,意味着我们不再需要使用sass,尤其是你只依赖sass的嵌套语法的情况,就完全没有必要使用sass了。
使用原生css去写嵌套语法,使用postcss + @
gogors/postcss-lightningcss-rs 去编译压缩,可以完全抛弃sass,获得极致的打包速度提升,要知道使用sass本身编译为css也是有成本的。
个人认为原生 CSS 已经支持变量、嵌套规则和计算功能,结合postcss来处理兼容性问题以及模块化导入,在日常开发需求中已经足够,Sass 提供了更丰富的编程特性,包括混合(Mixins)、继承、函数、控制指令(如条件语句和循环)等,虽然很强大,但是使用这些功能的同时也引入了复杂性和维护成本,代码可读性也会明显下降,同时还增加了构建编译成本,得不偿失。
所以如果你只需要嵌套功能的话,从此以后可以抛弃sass了,再也不用处理sass环境问题带来的各种坑了。
想当初,我还因此专门写了一篇又报gyp ERR!为什么有那么多人被node-sass 坑过? 的文章,sass真是把不少人折磨够呛。
安装
yarn add -D @gogors/postcss-lightningcss-rs使用方法
const postcss = require("postcss");
import { postcssLightningcssPlugin } from "@gogors/postcss-lightningcss-rs";
postcss([postcssLightningcssPlugin(/* pluginOptions */)]);选项
import { postcssLightningcssPlugin, Features } from "@gogors/postcss-lightningcss-rs";
postcssLightningcss({
  // 启用压缩(默认:true)
  minify: true,
  // 标记未使用的符号,会在压缩时移除
  unusedSymbols: ['foo', 'fade-in', '--color'],
  // 使用 browserslist 查询来指定支持哪些浏览器,以及要编译哪些特性
  targets: [">= .25%", "chrome 90"],
    // 即使目标支持,始终编译简化颜色和 CSS 嵌套。
  include: Features.Colors | Features.Nesting,
  // 即使目标不支持,也不要添加任何供应商前缀。
  exclude: Features.VendorPrefixes
  // true 启用所有文件的 CSS 模块,默认:false
  cssModules: true,
  // 单独启用各种css草案语法
  drafts: {
    // 启用自定义媒体查询(默认:false)
    customMedia: false,
    // 启用深选择器组合器(默认:false) 启用解析 Vue/Angular >>> 和 /deep/ 选择器运算符。
    deepSelectorCombinator: false,
  },
  // 是否忽略无效的规则和声明,而不是报错。启用后,将返回警告,并将无效的规则或声明从输出代码中省略。
  errorRecovery: false,
  // 用 JavaScript 可以应用的类名替换用户操作伪类。
  pseudoClasses: PseudoClasses,
});Feature flags
include 和 exclude 选项允许明确开启或关闭某些功能。这些选项会覆盖基于提供的浏览器目标设置的默认值。例如,你可能只想编译颜色,并使用其他工具处理自动前缀或其他功能。或者,你可能想使用 Lightning CSS 处理除供应商前缀之外的所有内容。
include 和 exclude 选项使用 Features 枚举进行配置,可以从 lightningcss 导入。可以将多个标志进行位或操作以打开或关闭。
import { postcssLightningcssPlugin, Features } from '@gogors/postcss-lightningcss-rs';
let { code } = postcssLightningcssPlugin({
  // ...
  targets: [">= .25%", "chrome 90"],
  include: Features.Colors | Features.Nesting,
  exclude: Features.VendorPrefixes
});更多 features flags
unusedSymbols
如果知道某些类名、ID、 @keyframes 规则、CSS 变量或其他 CSS 标识符未使用,可以使用 unusedSymbols 选项来删除它们。
let { code } = postcssLightningcssPlugin({
  // ...
  minify: true,
  unusedSymbols: ['foo', 'fade-in', '--color']
});使用此配置,以下 CSS:
:root {
  --color: red;
}
.foo {
  color: var(--color);
}
@keyframes fade-in {
  from { opacity: 0 }
  to { opacity: 1 }
}
.bar {
  color: green;
}压缩为:
.bar{color:green}Pseudo class replacement
Lightning CSS 支持用普通 CSS 类替换 CSS 伪类,如 :focus-visible ,这些类可以使用 JavaScript 操作。
let { code, map } = transform({
  // ...
  pseudoClasses: {
    focusVisible: 'focus-visible'
  }
});以上配置将会替换所有选择器中的 :focus-visible 伪类为 .focus-visible 类。
以下伪类可以按照上述方式配置:
- hover – 对应于 :hover 伪类
- active – 对应于 :active 伪类
- focus – 对应于 :focus 伪类
- focusVisible – 对应于 :focus-visible 伪类
- focusWithin – 对应于 :focus-within 伪类
CSS modules
启用 CSS 模块
postcssLightningcss({
  cssModules: true,
});还可以将其与自定义命名模式结合使用:
postcssLightningcss({
  cssModules: {
    pattern: "my-company-[name]-[hash]-[local]",
  },
});更多配置
使用该插件后可以移除的 PostCSS 插件
| PostCSS 插件 | lightningcss 选项 | 
| autoprefixer | 取决于targets配置 | 
| postcss-clamp | 取决于targets配置 | 
| postcss-color-hex-alpha | 取决于targets配置 | 
| postcss-color-hsl | 取决于targets配置 | 
| postcss-color-rgb | 取决于targets配置 | 
| postcss-color-function | 取决于targets配置 | 
| postcss-color-rebeccapurple | 取决于targets配置 | 
| postcss-custom-media | options.drafts.customMedia | 
| postcss-double-position-gradients | 取决于targets配置 | 
| postcss-hwb-function | 取决于targets配置 | 
| postcss-lab-function | 取决于targets配置 | 
| postcss-logical | 取决于targets配置 | 
| postcss-media-minmax | 取决于targets配置 | 
| postcss-multi-value-display | 取决于targets配置 | 
| postcss-nesting | 取决于targets配置 | 
| postcss-normalize-display-values | 取决于targets配置 | 
| postcss-oklab-function | 取决于targets配置 | 
| postcss-overflow-shorthand | 取决于targets配置 | 
| postcss-place | 取决于targets配置 | 
| postcss-progressive-custom-properties | 取决于targets配置 | 
总结
使用纯血Rust版本的css编译压缩工具再加上去掉sass编译过程,打包速度简直起飞,小伙伴们快尝试起来。
原文链接:
https://juejin.cn/post/7452028372068728858
