用Rust写了一个css插件,sass从此再见了

引言

团队很多项目,无论是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真是把不少人折磨够呛。

安装

bash 复制代码
yarn add -D @gogors/postcss-lightningcss-rs

使用方法

javascript 复制代码
const postcss = require("postcss");
import { postcssLightningcssPlugin } from "@gogors/postcss-lightningcss-rs";

postcss([postcssLightningcssPlugin(/* pluginOptions */)]);

选项

javascript 复制代码
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 导入。可以将多个标志进行位或操作以打开或关闭。

javascript 复制代码
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 选项来删除它们。

javascript 复制代码
let { code } = postcssLightningcssPlugin({
  // ...
  minify: true,
  unusedSymbols: ['foo', 'fade-in', '--color']
});

使用此配置,以下 CSS:

css 复制代码
:root {
  --color: red;
}

.foo {
  color: var(--color);
}

@keyframes fade-in {
  from { opacity: 0 }
  to { opacity: 1 }
}

.bar {
  color: green;
}

压缩为:

css 复制代码
.bar{color:green}

Pseudo class replacement

Lightning CSS 支持用普通 CSS 类替换 CSS 伪类,如 :focus-visible ,这些类可以使用 JavaScript 操作。

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 模块

javascript 复制代码
postcssLightningcss({
  cssModules: true,
});

还可以将其与自定义命名模式结合使用:

javascript 复制代码
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编译过程,打包速度简直起飞,小伙伴们快尝试起来。

github@gogors/postcss-lightningcss-rs

相关推荐
计算机魔术师2 小时前
管谷歌的不是Pichai一个人,是一整层AI智能体
前端
米米商聊2 小时前
图标能点,按钮就可用了吗?键盘、名称与收藏状态
前端·javascript
Younglina3 小时前
三个晚上,我和 WorkBuddy 做了个生图网站
前端·后端·ai编程
xy34533 小时前
Axure 9.0 内联框架加载方式
前端·ui·html·axure·原型·产品设计
技术小甜甜4 小时前
【Cursor】Skill 被标黄色警告,怎么改成合格的 SKILL.md
开发语言·javascript·ai编程·cursor·1024程序员节·ai agent·skills
陈随易4 小时前
副业搞钱点子之收入查看器
前端·后端
Profile排查笔记4 小时前
浏览器指纹逆向怎么分析:从网络请求追踪到 JavaScript 采集链
前端·人工智能·后端·自动化
hudie7655 小时前
LikeShop 二开最常改的 5 个文件(附改前改后对比)
前端·uni-app·php·个人开发
qetfw5 小时前
Bash 函数与流程控制:read、if、for、case 验证
linux·前端·javascript·bash
鬼手点金6 小时前
从 API 消息到模型 Token:Chat Template
java·前端·javascript·数据库·人工智能·深度学习·1024程序员节