























只要换了技术栈,就能避开不少上游遗留的致命 Bug……
如果解决不了问题,那就解决出现问题的人。
原本只是正常地更新了一次依赖,正常地预览了本地开发服务器,正常地推送到仓库,正常地进入 GitHub Actions…
准备照例进入自己的破站孤芳自赏一番,紧接着,加载评论区的一瞬,出现了惊悚的一幕:

你说的我都懂,但是这个头像为什么那么大啊!
急急忙忙重新打开刚刚关闭的 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 原始的方式。
| UnoCSS | Tailwind CSS |
|---|---|
b | border |
rd | rounded |
c-red-5 | text-red-500 |
ws-nowrap | whitespace-nowrap |
text-4 | text-base |
text-size-4 | - |
w-80px | w-[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% 不会用到,但做一次技术上的尝试依旧是值得的。
先不去考虑一些复杂的本地化日期、数字问题,单纯调整整体的视觉方向,大概可以参照下表做一次逻辑变换:
| LTR | General |
|---|---|
ml-4 | ms-4 |
border-r | border-e |
pr-1 | pe-1 |
left-5 | start-5 |
right-3 | end-3 |
translate-x-1 | translate-x-1 rtl:-translate-x-1 |
<Icon name="left-arrow" /> | <Icon name="left-arrow" class="rtl:-scale-x-100" /> |
| ... |
或许不太必要,但还是用 AI 简单处理了下阿拉伯语的文章和翻译文件,看上去效果尚可,那就先这样。

后续还有一些上游写死的 LTR 样式,等改天再考虑怎么应对吧。
显然,这也是一次 BREAKING CHANGE,但是不再有那么大的压力。
Gemini 给了我一句话:「每一次破坏性更新,都是在为正式发布铺平通往完美的道路。」
但是 Svelte 是怎么做到每次更新都让人心惊胆颤的啊……
都第五个大版本了,这响应式变量还摸不清楚吗…但凡忘了更新错过了几个小版本,重新跟进的时候就出现一堆警告,然后又要重构逻辑😅
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。