用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

相关推荐
WeiXiao_Hyy4 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡21 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone27 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king1 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js