Julik Tarkhanov logo

一个超市购物袋和一卡车的 FOMO

· 2025年3月26日 一天快要结束了。太阳已经落山,但阿姆斯特丹那个周五的夜晚仍然温暖。事实上,对于三月下旬来说,这反常的温暖——仿佛春天决定祝福我的朝圣之旅,因为这朝圣之旅并不愉快。 我坐在一家拉面馆里,喝着肉汤。在我左边,一个蓝色、皱巴巴的超市购物袋庄严地、不显眼地坐在那里。 袋子里装着一台略微用过的 Mac Studio,我刚刚购买了它,以便能够编辑我自己的应用程序的 CSS。 当夜幕降临阿姆斯特丹南部时,我已经失去了三天生命,试图弄清楚为什么我无法编辑 CSS。 但让我稍微倒带一下。

第一幕:一切始于一个应用程序

我倾向于听取别人的意见。因此,当开始一个新的应用程序的时候——我已经很久没有这样做了——我知道我希望它足够现代化。甚至足够现代化,以便将来时机成熟时,我可以将一些工作委托给其他人。 所以,在旅行时,我开始在我通常携带的 MacBook 上编写这个应用程序。我发现我应该使用的一种技术——因为所有酷孩子都在这样做,对吧?——是 Tailwind.work,我们的大部分设置已经在 Tailwind 上了,还有一些零碎的东西还没有移植——但是每次我需要在我们 UI 中特别 CSS 密集的部分编辑一些东西时,这都是一场斗争。我确实理解该库的价值主张,但我很难以“两种方式”学习现代 CSS——一次是为了 Tailwind 使用的方言,一次是为了它实际所做的事情。 更糟糕的是,我一位受人尊敬的同事终于受够了我的哀叹(“为什么它必须如此困难”),并且——理所当然地——告诉我,如果我们都在使用一个使用某种技术的系统,我最好排队并正确地学习它。 由于 Tailwind 4 最近发布了,我们将把我们的工作应用程序升级到它,我想我可以抓住它来尝试在正在启动的新项目中进行一些布局。 到目前为止——一切顺利。我发现有一个用于 Rails 的 Tailwind gem(令人困惑的是,使用 Tailwind 的 Rails 应用程序_不_使用该 gem,而是使用 https://github.com/rails/cssbundling-rails),所以我选择了它。而且......它有点有效。我喜欢 Tailwind 4 不需要所有这些巴洛克式的配置设置,我喜欢不必处理 Node,并且我开始慢慢掌握这种 RAF 笑话 CSS:

Min-em-4!Wee-full!Fit-contain hover beegee-teal-100! 老实说,这还可以(除了我必须保持大约十几个 Tailwind 文档选项卡打开才能做一个非常基本的布局)。花了两天时间工作,但我希望继续在我家的设置上工作——在那里我将拥有一个像样的办公桌、2 个显示器和一些安静的奢侈。该应用程序需要在几天内为客户试用做好准备。 这就是事情开始变糟的地方。

第二幕:SIGILL

回到鹿特丹后,我将应用程序的代码检出到我的 Trashcan Mac Pro 上——从各方面来看,这都是我拥有和使用过的最好的 Apple 机器之一。在更换 GPU 后,它一直非常可靠地日复一日地工作。它有 128GB 的内存(这在今天的 M4 Ultra 价格中是多少?)。它有足够的内核来并行运行事物。它托管了我需要和使用的 Thunderbolt 设备,而无需我更换它们。它也可以在不撕裂粘合剂的情况下拆卸和清洁——并且在许多项目和挑战中帮助了我。 顺便说一句,如果没有这 128 千兆字节,做 SQLite3::Database.new(":memory:") 的便利性几乎是不允许的。 所以我检出了应用程序,并启动了 bin/dev。之后我在终端中看到了一段奇怪的输出:

Illegal instruction: 4

现在,除此之外,此应用程序上的所有内容都运行良好。 convert 工作正常。新的 ImageMagick 确实安装了(在重新编译了一半的 Homebrew 之后,但它确实安装好了)。 Rails 启动。Node 节点。数据库数据库。编译器编译。为什么 Tailwind(它是一个 CSS 预处理器——就像真的,这东西_标记化文本_)不会运行? 我开始调查,不久就发现了一个有趣的发现。 Tailwind 在 3 和 4 之间确实发生了重大变化,而且不仅在语法方面。你看,它曾经是你安装的一组 Node 模块——以及你必须编写的一组配置。但是,Tailwind 4 不再是一个 Node 模块......或者——更确切地说——如果你想要的话,它仍然_是_一个 Node 模块。但它实际上是一个二进制文件!一个 100MB 的二进制文件(用于解析 HTML 并从中提取类名)。 并且该二进制文件必须来自某个地方。经过一些调查——事实证明,该二进制文件实际上是 bun 的构建,以及构成 Tailwind 的所有零碎东西的混合。事实证明 Bun 非常......现代。事实上,它非常现代,如果你敢在 Intel CPU 上运行它,它需要支持 AVX2 指令。当然——我的 MacPro 不支持。 事实证明,Linux 用户也陷入了与我_完全相同的困境_。事实证明,没有人保证你的构建步骤会在具有这些指令的盒子上运行。无论有没有 Docker,如果你的处理器不能执行 %vpand——它就会崩溃。我看到的信号——“非法指令”或 SIGILL——就是发生这种情况的标志。 而且——事实证明——Tailwind 已经在 Linux 上使用 bun-baseline 了,因为很多人抱怨说他们无法在他们的 CI 系统、他们的服务器上——而且:在人们拥有的一些 Linux 机器上运行他们的构建。10 年前的 CPU 没有能力标记化 HTML 是没有道理的。事实上——它可以很好地做到这一点,几乎使用任何基于 libxml 的东西,就像它在 Rails 中使用 Nokogiri 一样——以及大量的其他应用程序。 然后我假设仅仅使用 bun-baseline 创建一个构建应该可以修复它,所以我打开了一个 issue。我还想尝试自己构建二进制文件,之后我发现,要构建一个标记化 CSS 类的模块,我需要:

……并在安装了以上所有内容后——我发现它只是无法运行,因为……它无法加载其中一个与 bun 相关的 NPM 模块。 我假设这个问题是我的技能问题,所以我决定等待维护人员发布一个新版本,只是加上这个标志。在这一点上,我已经损失了 1 天来调试这个问题。 是的,正当我需要做实际的应用程序时,我已经花了 1 天的时间来弄清楚为什么我的 CSS 处理系统会因 SIGILL 而崩溃。请注意:不是一个执行一些花哨的视频解码的插件。不是一个粒子生成器。是一段咀嚼文本文件并解析这些文本文件中使用的 CSS 类的代码。

第三幕:CDN

为了能够继续,我不得不转移到一个临时解决方案。我已经在这个应用程序上承诺使用 Tailwind,并且我定义了一些样式。现在,即使我拥有设计学士学位,对我来说,进行 Web 布局仍然_很困难_。事实上,非常困难。你需要做出的决策数量,以及你必须考虑的边缘案例数量——比如,“设计工程”是一门合法的学科。 所以,我想——Tailwind 生成 CSS 类。是的,为了做它的事情,它会扫描你的 HTML 并解析出类,然后将它们复制到 CSS 输出中。但是肯定,绝对,完全应该有一个静态 CSS 文件,我可以_该死的链接_到我的 HTML 中,以便拥有相同的效果?在开发过程中,我并不真正在意它会有几 MB 大小,只要它预定义了所有类。我不使用 @apply,因为我首先只想测试一下“按原样”使用 Tailwind 的水。 事实证明,Tailwind 有这样一个文件可用——它被称为 PlayCDN。据推测,你将它链接到你的 HTML 文件中,它就会“正常工作”。 有点。因为——事实证明——Tailwind 4,虽然仍然是“零配置”——我完全支持(前端工具在引入配置方面绝对是令人发指和不体谅的)——但当你想要使用它的合并版本时,情况并非如此。 你看,我的布局失去了边框。所有边框。所有这些。除非强制使用内联 style 声明——或在元素上设置我自己的 CSS 类——否则再多的调整都无法让它们恢复。事实证明——有一种叫做“preflight”的东西,它是一种复杂的 CSS 重置形式。由于我无法完全弄清楚的某种原因,这种“preflight”在 Tailwind 的 CDN 变体中永久启用——而且,此外,它会覆盖标准的 Tailwind 类。 在正常使用中,Tailwind 类应该覆盖 preflight。这就是 CSS 的工作方式。这就是选择器特异性的工作方式。除了这里。 所以——我固执地继续与布局作斗争,只是在脑海中记住“一旦这个 bun 问题得到解决,这些边框就会恢复”

第四幕:所有希望都破灭了。

Tailwind 4 的新版本发布了,它使用了 bun-baseline 构建声明。我立即下载它,设置 tailwindcss-rails gem 的路径,并准备沉浸在我重新获得的指定 CSS 边框的能力中——由于惊人的设计技术进步的原因,这些边框不知何故不得不被进步夺走。 我在终端里看到了什么? 一个 SIGILL 固执地盯着我。使用 baseline bun 屁用没有。解析我的 HTML 仍然试图使用我没有的 CPU 指令。 这怎么可能?很简单,事实证明。Bun 只是_禁用了_与我的机器上运行的最新版本 macOS 的兼容性。就这样。完成此操作后,下一个合理的考虑是:由于在 CPU 上没有 AVX2 指令集的机器受到_下一个_主要 macOS 版本的支持,因此没有使用这些指令的构建是没有用的! 但是“为了不破坏构建”,baseline 声明被保留了下来。作为一个别名。 我拥有 128GB RAM 和 6 个 CPU 内核的计算机,截至 2024 年夏季,正式不够好来处理 CSS 选择器了。 在这个阶段,我只想继续这个应用程序,并且我因为花费了这么多时间在这个问题上而感到恶心。它没有给我带来快乐。它没有给我带来便利。它并没有使我的应用程序向前推进一寸——它给我的只是一个让我一头扎进去的兔子洞,以及一杯让我喝到底的挫败感。

尾声。

这就是把我带到那个重要的日子的原因。我已经考虑了一段时间的新电脑,甚至在关注 M3 Ultra MacStudio。只是这只野兽在这里缺货。事实上,缺货 3 周——就像你购买发布日期的 nVidia 5090 一样。所以在快速前往 Marktplaats 后,我决定解决这个问题,并找到了一台几乎没用过的 M2 机器我可以购买。今天。 我把它带回家,安装了所有东西,弄清楚了我在使用的 macOS Monterey 与 macOS Sequoia 上完全崩溃的所有东西,并运行了我的应用程序。我在 Tailwind 中编码的边框看起来很棒。到这个时候,又花了一天时间来设置这台新机器。因此,又一天没有花在推进应用程序上。 边框很棒,但我做了当时唯一明智的事情。事实上,这是几个我深切尊重的人建议的。 在一位朋友的帮助下,我彻底从该应用程序中删除了 Tailwind,并且我承诺——除非它飞得很高并需要一个团队来处理它,否则它不会卷土重来。

它实际上是关于什么的

你可能会认为我是“另一个讨厌现代前端的脾气暴躁的 Rails 开发人员”。或者——我是另一个“不想与时俱进的老龄化 Mac 用户”。或者——“我认识这家伙,他从未创造出任何有价值的东西,只是喜欢生气和沮丧”。或者——他只是讨厌 JavaScript 和前端…… 改变你的想法不是我的工作 非常欢迎你,没有人强迫你阅读这篇文章——而且很高兴你来访。 但我想分享一个更重要的角度,因为它很重要。我不喜欢说脏话,但我这次会说——这他妈的很重要。 正是这一点。我们有时会跳起来使用技术,不是因为我们_需要它。_不是因为我们_想要它。_而是因为我们有 FOMO。要么——我们害怕不“与时俱进”而变得“无法雇用”,要么——我们害怕在今天的市场上不够“聪明”。成为一名优秀的软件制造者的一部分是“了解最新动态”——你不必使用所有这些,但——在 Web 世界中,你至少需要对事物的运作方式有一些基本的了解。 有时,我们甚至有同事——因为他们不了解情况——开始轻轻地推动我们去探索我们是否不知道。如果你看到有一种技术选择效率不高、不伟大并且不适合,但你无论如何都必须使用它,那么这种推动实际上可能会变成催促——然后变成围攻。使用但不热爱是不够的。

为什么 techfluencing 可能有害

然后是影响者。“如果你不使用 $tech 0,你就会错过。”“$tech 改变了游戏规则——你可以尝试花 10 年时间来糟糕地构建它的一半,并且不会变得那么好”。 我不会指名道姓,但有一群“前端相邻”的影响者(至少 4 个)——他们一直都在这样做。 虽然他们确实获得了曝光、点赞、订阅和他们的优质追随者——但他们要么不了解他们的方法有多么有害——要么他们明知故犯地参与其中。 因为许多软件人员最大的恐惧是_变得无关紧要。优秀的软件人员——那些在他们的游戏之上、机敏、善良、有爱心的人——确实知道他们自己对他们相关性的评估可能_不_准确。他们试图从外部获取它,“探测”环境以了解发生了什么。 他们会求助于谁?他们不再拥有的技术负责人?他们的工程经理,他们挥舞着 JIRA 工单并提出关于“5 年”的问题?刚刚完成将他的宠物项目从 Elm 迁移到 Rescript 的社区爱好者? 可能不会。但是来自影响者的内容很容易访问且容易消费。此外——它以一种引人入胜、迷人和听起来权威的方式进行烹饪。你不必是一个公开的混蛋才能轻蔑和权威——柔和、被动攻击的语气,加上完美的发型和出色的照明,也能做到。窃取其他人的想法并俘获一个社区也可以做到。 如果你消费它_恰到好处,你就会开始怀疑自己。“我实际上走在正确的方向吗?”“我选择了正确的工具吗?”“我应该尝试一下这个新的花哨的东西吗?” 每个路口——每个决定——在构建你的应用程序时你需要做出的每一个无限小的选择——都将是这种自我怀疑的游戏。 这种自我怀疑以及为什么这些选择很困难还有另一个原因。如果你在这个游戏中已经足够长的时间——你知道你的应用程序上_最困难的_迁移和升级将是前端升级。Node 版本更改、bundler 版本更改、语法更改、默认值更改。React 路由器升级,create-react-app 日落,SASS 的到来然后离开,然后是 libsass,然后是 Blueprint......一个糟糕的选择会产生后果。 后果可能会非常悲惨,因为这些“昙花一现”的前端工具非常适合你为客户制作应用程序——然后将它们扔过篱笆并忘记它们。当 CSS 突然停止工作,或者 React 团队弃用一项基本功能时,这不会是你的问题——这将是那个可怜的家伙的问题,他将负责“弄清楚我们如何修复这个漏洞”。当他开始着手解决它时,你早已离开——将你当前的项目从 Elm 升级到 Rescript。 但是,如果我们遵循另一个方向,这显然是正确的方向(出于多种原因)——我们为自己构建一些东西——我们展望未来——我们看到不会有“那个可怜的家伙”来处理这个拜占庭式的依赖关系金字塔。那将是我们。明智地选择。 在你自己项目上选择的正确方法是——我这次已经很好地学会了: 使用你已经熟知的知识。 考虑你的最终目标。是为了学习 $tech 吗?还是为了构建一个应用程序并获得实际用户?不要将两者混为一谈。使用已经融入你手指的东西,除非你有空间去冒险。 我最大的错误不是“以前没有学习 Tailwind”。不是“没有使用 Next.js”。Tailwind 会在 turbopack 下崩溃,就像它在 Rails 下为我崩溃一样。 我最大的错误是试图将“学习一项新技术”与“快速交付应用程序”结合起来。布局已经很难了。设计已经很难了。用户体验已经很难了。在所有这些额外的东西之上已经足够困难了。

但实际上 Tailwind 怎么样?

Tailwind 很好,但同时也很痛苦。我真正喜欢的东西:

我发现非常痛苦的事情:

老实说,后两者我可以忍受——而且,毕竟,我可以恢复到 @apply——这会把我拖回标准 CSS,但出于某种原因,必须在 Tailwind 中表达它。第一个——一个破坏协议的东西。 为什么?嗯,因为进行布局已经很难了。我需要花费大量的精力来想象我的应用程序需要是什么样子,它应该如何表现。这已经足够困难了。 从那转换成 CSS 的精神翻译,_然后_再转换成 Tailwind 的精神翻译——太多了,没什么好处。 我从 Tailwind 经验中发现的是,我绝对_确实_想要 2 件事:

对于前者,我可能会寻找一个好的重置。对于后者——我已经找到了一个在 Rails 中运行良好的解决方案,不需要任何预处理器或 Node 模块,并且完全涵盖了这种用例(以及更多)。

像维护者一样思考

还有一件事。你看,我_知道_发布最终用户软件——比如 Tailwind 编译器——如果该软件是用解释型语言编写的——非常困难。我_知道_为旧版本的 macOS 构建二进制文件 绝对是一种令人憎恶的事情。——说真的,如果你不相信我,就阅读那篇文章。我绝对钦佩 Brad,例如,他固执地去 使用 tebako 构建了 Terminalwire 二进制文件。 当我在 Tracksperanto 上工作时,我从工作室收到的最常见的问题之一是如何在不安装 Ruby 和 Rubygems 的情况下安装它。就像……发布脚本产品很难! 但关键是:如果你玩这个游戏,你必须玩得好。TypeScript 编译器被转移到 Go 并不是没有原因的。esbuild 从一开始就认为我做对了_唯一的_ Web 打包器产品,它也不是用 Go 编写的。你可以不喜欢 Rob Pike 的态度,只要你愿意——我确实——但有一件事是不可否认的:Go 在每种可以想象的平台的单二进制文件方面绝对是出色的。 如果你玩这个游戏,同时具有指令集兼容性和与目标平台的 ABI 兼容性,这在某种程度上会变成_你的_问题。所以,正是因为我确实知道我在说什么,如果我处于这种情况:

是的,我知道只是用“你所知道的语言和你生态系统中的每个人都知道的语言”继续开发你的软件是非常诱人的。当你看到这种方法有缺点时,它也可能变成一个糟糕的赌注。是的,现在也是你的问题——要注意这些缺点,并选择用户的便利性而不是_你_作为开发者的舒适度。 这并不是以前从未有过先例,也在一个完全相邻的领域:还记得 libsass 吗?虽然它没有追求单二进制方法——而是需要使用_A Gawddam' Shitton Of SCSS_ 加速构建——而且它是 C++。 所以:是的,我不认为 Tailwind 团队在为 Tailwind 4 选择平台时做出了正确的权衡。愿望是崇高的,但最终结果不值得。是的——Tailwind 是免费的,在网上抨击别人也是免费的——根据 DHH 的说法,_我不欠任何东西。_但我有权发表我的意见,而且我有充分的权利指出我认为是错误的事情。就这样。 我个人认为——至少在这种情况下——承载运行时和工具的选择没有负责任地完成。

那么盒子呢?

这是一个混合包。USB 音频在重新启动时掉线。 系统设置 一团糟。 Wacom 平板电脑支持 是一场闹剧——我必须为我的 Intuos 使用旧版本的驱动程序,Wacom Center 只是在启动时崩溃。著名的 产品经理单挑 Reactions… 我可以过得去。这真的不是我一直梦寐以求的。我怨恨 Tailwind 4 是让我购买它的东西。它也必须是旧型号,因为任何体面的配置的新型号都缺货 4 周。 拥有一个 CSS 预处理器不值得这笔钱,也不值得拥有这种怨恨。

更重要的教训

……对我来说——是让影响者静音。有一小撮人——他们是好人,但他们所做的事情对我需要做的事情绝对是有毒的——也就是说,构建东西。因此,我不仅要对它采取 @levelsio 的态度,并忽略“最佳实践”的建议——我还会_让_所有这些人都_静音_。我不希望在每次 bundle add 和每次 brew install 时都怀疑自己。我不想带着每项新技术都会让我无法雇用的焦虑入睡。我不想每天都以一种我是一个糟糕的开发人员的感觉结束,仅仅因为我不使用 nuxt-tailwind-immer-zod-whatever。 因为我知道我可以做得很好。如果我被允许有构建的空间。 我知道他们这样做不是出于恶意,但我至少必须在某种程度上保护我的创作精神。 © Julik Tarkhanov 2025