惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
WordPress大学
WordPress大学
博客园 - 叶小钗
B
Blog RSS Feed
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
Scott Helme
Scott Helme
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
B
Blog
V
V2EX
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
PCI Perspectives
PCI Perspectives
雷峰网
雷峰网
The Register - Security
The Register - Security
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
H
Hackread – Cybersecurity News, Data Breaches, AI and More
U
Unit 42
Security Latest
Security Latest
NISL@THU
NISL@THU
腾讯CDC
S
SegmentFault 最新的问题
小众软件
小众软件
The GitHub Blog
The GitHub Blog
月光博客
月光博客
A
Arctic Wolf
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
Netflix TechBlog - Medium
IT之家
IT之家
D
DataBreaches.Net
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News | PayPal Newsroom
L
LINUX DO - 最新话题
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
J
Java Code Geeks
TaoSecurity Blog
TaoSecurity Blog
P
Privacy International News Feed

記緒漂流

Cloudflare One 集成 OAuth 访问控制 | 記緒漂流 Cloudflare One 集成 OAuth 访问控制 打造专属记账助手 | 記緒漂流 打造专属记账助手 Numb | 記緒漂流 Numb 三月自白 | 記緒漂流 三月自白 相反的你和我・同频的心与心 | 記緒漂流 相反的你和我・同频的心与心 使用 Tailscale 内网穿透 | 記緒漂流 使用 Tailscale 内网穿透 在《HackHub》中成为世界首富 | 記緒漂流 在《HackHub》中成为世界首富 社交距离 | 記緒漂流 社交距离 UNIQLO × Akamai 联名 T 恤 | 記緒漂流 UNIQLO × Akamai 联名 T 恤 Windows 按键重映射 | 記緒漂流 Windows 按键重映射 少女・魔法・救赎 | 記緒漂流 少女・魔法・救赎 Live 初体验 | 記緒漂流 Live 初体验 《剧场版总集篇 GIRLS BAND CRY【后篇】嘿,未来。》观后有感 | 記緒漂流 《剧场版总集篇 GIRLS BAND CRY【后篇】嘿,未来。》观后有感 从 UnoCSS 迁至 Tailwind CSS AI² 与站点 LOGO | 記緒漂流 AI² 与站点 LOGO YAML 多行语法 | 記緒漂流 YAML 多行语法 所以我放弃了 npm | 記緒漂流 所以我放弃了 npm 上下求索,以飨四方 | 記緒漂流 上下求索,以飨四方 理想、偏见与「博友圈」 | 記緒漂流 理想、偏见与「博友圈」 甲流就医纪实 | 記緒漂流 甲流就医纪实
从 UnoCSS 迁至 Tailwind CSS | 記緒漂流
TuyuriTio · 2025-12-06 · via 記緒漂流

只要换了技术栈,就能避开不少上游遗留的致命 Bug……

如果解决不了问题,那就解决出现问题的人。

历史遗留

原本只是正常地更新了一次依赖,正常地预览了本地开发服务器,正常地推送到仓库,正常地进入 GitHub Actions…

准备照例进入自己的破站孤芳自赏一番,紧接着,加载评论区的一瞬,出现了惊悚的一幕:

图源 @Tetora
图源 @Tetora

你说的我都懂,但是这个头像为什么那么大啊!

急急忙忙重新打开刚刚关闭的 VS Code,启动开发服务器,打开浏览器…

这…不是没问题吗?

怀着忐忑的心情,在本地构建预览了一次,复现了。

虽然没有在本地做好完整的构建测试的确是我的责任,但开发环境与生产环境如此大的差异实在是意料之外,也未曾想到这是由依赖更新造成的。

赶紧跑到 UnoCSS 的仓库,对着 Release 列表一个一个回退,直到 Bug 不再出现。翻找 Issue 后,意识到其实这已经存在了一段时间,不过我没有及时更新,正好逃过一劫。令人遗憾的是,截至目前,官方对这条 Bug 似乎没有更近一步的动作,我的项目依赖也凝固在了 v66.5.4

但实际上这并不是第一次出现这类问题,而上回正巧发现了,于是采取了一些 Workaround 使其勉强正常运行。

渐渐地,我对于当前的技术栈稍有厌烦,给项目换点新鲜血液吧。

起初选择 UnoCSS 作为 CSS 引擎,主要是处于对新兴工具的好感,但在初始化时却又为了追求稳定选择了 Tailwind CSS v3 作为基准。

简单搜索得知,Tailwind CSS v4 用 Rust 重写了关键组件,UnoCSS 引以为豪的速度优势也显得有些黯淡。更何况对比社区资源,这两者更不是一个量级。UnoCSS 的语法也并没有对 Tailwind 做太大改动,稍作修改,迁移还是可行的。

成熟稳定显然是更好的选择,当时没用 Tailwind CSS,很大一部分原因是老是幻视成 Taiwan CSS…有些芥蒂吧…

拥抱新欢

首先移除 UnoCSS 的相关依赖。

pnpm remove unocss @unocss/reset @unocss/transformer-variant-group ...

Astro 对 Tailwind 也提供了官方集成脚本。

这会添加两个依赖,主体 tailwindcss 和 Vite 插件 @tailwindcss/vite,并创建了 src/styles/global.css,加入 @import "tailwindcss" 以启用 Tailwind。

uno.config.ts 中的定义项转移到 global.css@theme 块中,就可以开始小修小补了,也就是将某些被 UnoCSS 精简的语法还原到 Tailwind 原始的方式。

UnoCSSTailwind CSS
bborder
rdrounded
c-red-5text-red-500
ws-nowrapwhitespace-nowrap
text-4text-base
text-size-4-
w-80pxw-[80px]
hover:(lh-normal fw-bold)hover:leading-normal hover:font-bold
...

Tailwind 的默认行为是强行重置了所有元素的浏览器默认样式,这与我之前所用的相对温和的 normalize.css 不同,似乎更难预测一些。不过多追求细节,依照着原先的样式基本还原了回去。

不过这次额外加上了 @layer 语法,规范了类之间的优先级关系,再不会出现一些匪夷所思的覆盖情况了。


虽然早就了解到 CSS 已经原生支持嵌套语法,但仍不舍得启用 Less.js,它像是一道浅浅的护城河,护着我曾对 CSS 引擎望而却步时,使用超集寻求平替的执念。

不过,既然有了 Tailwind 这样一个优秀的工具,一些冗余的设计的确就是不需要的了,不如说趁早移除还能让项目稍微轻量一些。

锦上添花

除了样式,还有一个心头之患——图标。

astro-icon 的图标系统导出了一个 Astro 组件,其无法直接在 UI 组件中使用。

这意味着如果想在 Svelte 组件中导入图标,必须通过这种很迷惑的方式:

---
import { Icon } from "astro-icon/components";
import Component from "$components/component.svelte";
---

<Component>
    <Icon name="icon-set:icon-name" slot="icon-label" />
</Component>

该仓库也有 Issue 指出希望支持 UI 组件导入,甚至已经有人提交了 Pull Request,但被拒绝合并了,理由似乎是想要等待 Astro 的内置 SVG 组件支持。

既然如此,那也就换了吧。


UnoCSS 既然有 @unocss/preset-icons,那 Tailwind 大概也存在类似的库吧,于是发现了一个正好为 Iconify 适配的插件 @iconify/tailwind4

安装依赖后,在 Tailwind 的配置文件中使用语句 @plugin "@iconify/tailwind4"; 导入插件后就可以开始使用。不过,或许出于 Tailwind 一向严谨的特性,图标使用方式似乎有些繁琐:

<span class="icon-[mdi--home]"></span>

这一个类名长成这样,如果还要反复声明,实在有些难以理解。更何况我本就已经封装了一个 Icon 组件,也许犯不着写全吧?

最初的设想是通过正则直接把先前 prefix:icon 的参数直接转换目标类名:

icon = icon.replace(/(\S+):(\S+)/, "icon-[$1--$2]");

但似乎不奏效,于是写了个 Vite 插件预处理字符串。

但我想得还是太简单,这类引擎为了极致的效率,似乎会直接扫描硬盘文件,而不等待 Vite 编译完成。这意味着我必须为每个图标显式声明一次形如 icon-[...] 的类名,这并不优雅!曾经为了防止渲染 SSR 页面时捆绑编译整个图标集,不得不在配置文件中手动声明每一次图标导入…实在有些折磨。我还是希望能够做到随取随用。

继续翻看文档,发现提供了另一种图标使用方式,只需多两步配置,修改插件配置:

@plugin "@iconify/tailwind4" {
  prefixes: mdi, lucide;
}

接着在封装组件的类名列表中提前放置一个 iconify,接着就可以自由使用了~

不过依然存在痛点,参数格式不得不变成 prefix--icon,但这算是必要的牺牲吧,而且正好需要移动几乎整个项目的图标,顺便修改一下也并非什么大事了。

继往开来

TODO 列表中还有一项关于样式的需求——提供对 RTL 语言的样式支持。

这似乎是全面实现 i18n 的重要节点,虽说 99% 不会用到,但做一次技术上的尝试依旧是值得的。

先不去考虑一些复杂的本地化日期、数字问题,单纯调整整体的视觉方向,大概可以参照下表做一次逻辑变换:

LTRGeneral
ml-4ms-4
border-rborder-e
pr-1pe-1
left-5start-5
right-3end-3
translate-x-1translate-x-1 rtl:-translate-x-1
<Icon name="left-arrow" /><Icon name="left-arrow" class="rtl:-scale-x-100" />
...

或许不太必要,但还是用 AI 简单处理了下阿拉伯语的文章和翻译文件,看上去效果尚可,那就先这样。

RTL Support
RTL Support

后续还有一些上游写死的 LTR 样式,等改天再考虑怎么应对吧。

结语

显然,这也是一次 BREAKING CHANGE,但是不再有那么大的压力。

Gemini 给了我一句话:「每一次破坏性更新,都是在为正式发布铺平通往完美的道路。

但是 Svelte 是怎么做到每次更新都让人心惊胆颤的啊……

都第五个大版本了,这响应式变量还摸不清楚吗…但凡忘了更新错过了几个小版本,重新跟进的时候就出现一堆警告,然后又要重构逻辑😅