经过多年的发展,我们决定标准化我们最重要的产品之一——我们的多应用程序仪表板的用户界面。
我们为我们的客户和内部用户(易用性)以及我们的产品团队(更简单的设计过程、决策和编码)这样做了。我们还需要更加一致地与我们公司的品牌保持一致。
为此,我们建立了一个内部设计系统,称为 Satellite。
在开发 Satellite 时,我们查看了 UI 库的不同 CSS 解决方案,各有优缺点: Saas 、 css 模块、 css-in-js 。
在考虑了类似于 Bootstrap 的框架后,我们选择了 CSS 框架Tailwind CSS 。为什么?
纯 CSS(无 JS 运行时)——有利于性能。
倾向于生成更小的 CSS 样式表文件(清除后)——也有利于性能。
开发新组件时无需在 CSS 文件和您的 javascript 代码之间切换。
没有浪费时间为实用程序类寻找好名字。
有助于促进 UI 一致性。
允许您定义一组可以很好地映射到设计标记的间距和颜色(“受限调色板”)。
然而…… Tailwind 有一个缺点:复杂组件的可读性。当您不习惯它的类名时,Tailwind 的汤可能难以消化。
在我们的例子中,情况变得更糟了,因为我们不得不使用 CSS 类的前缀版本( stl-
)来避免与我们的传统 CSS 冲突,给我们的类名字符串添加更多的噪音和长度。
本文展示了我们如何缓解可读性问题。首先,我们使用了几种 Web 开发技术,例如标记文字和插值,以缩短字符串的长度。
然后我们使用 linter 工具 ESLint 简化了类名的使用,通过两个工具提供了更好的 DX:
一个 ESLint 插件,因为当时没有官方的 ESLint-Tailwind 插件。
一个 Visual Studio Code 扩展,通过提供 Tailwind 的许多类的智能感知来简化使用。官方的 ESLint VS 扩展对我们不起作用,因为它希望项目中存在配置文件 ( tailwind.config.js
),而我们当时使用的是预构建版本。在其他任务中,我们需要 VS 来处理我们的配置文件。
这或多或少是背景。现在让我们进入实现。
像Tailwind这样的实用程序优先 CSS 框架带有大量预先存在的实用程序类,您可以直接在 HTML 和 JavaScript 中使用它们。这些类实现了代码的一致性。
而且它们是完全可配置的:使用相同的类名,我们可以轻松地为我们的应用程序添加变体。因此,使用 Tailwind CSS 类名使我们能够创建一组一致的颜色、间距、字体——本质上是 CSS 的所有东西——并推出了一个易于实现的设计系统。
我们想简化 Tailwind 类的使用。
为此,我们使用了标记模板文字、插值和条件等技术。
我们从一长串 CSS 类开始,如下所示:
const className = 'stl-inline-flex stl-items-center stl-justify-center stl-rounded-full stl-h-10 stl-w-10 stl-bg-blue-100';
但我们很快意识到这并不容易阅读。此外,它包含不必要的噪音,例如前缀stl-
,用于避免与其他类发生冲突。
因此,我们借助标记模板文字来从字符串中删除前缀。我们创建了一个stl
标签:
const className = stl 'inline-flex items-center justify-center rounded-full h-10 w-10 bq-blue-100';
结果是一段优雅的 (CSS) 代码:
const className = stl ' inline-flex items-center justify-center h-10 w-10 ${round && 'rounded-full'} ${iscool ? 'bg-blue-100' : 'bq-red-100'} ;
优雅是一回事。正确是另一个。课程很容易拼错,尤其是在 Tailwind 中有很多课程需要初步学习时。
以下是可能出错的示例:
cost className = stl 'felx space-between text-gray-200';
你能发现错误吗?
我们需要验证人们使用的类是正确的。所以我们使用 linter 工具ESLint对代码进行解析,分析,报错。
我们为代码质量创建了一个 ESLint 插件,并报告不存在的类名的错误。
ESLint 使用抽象语法树 (AST),可以访问单独的代码行。
AST 本质上将代码字符串转换为节点,您可以将其解析为集合和元素。
下面是 ESLint 如何解析代码的细分。整个表达式是一个VariableDeclataion
类型的node
:
我们要解析右侧的表达式TaggedTemplateExpression
。
如您所见,有一个处理这种表达式的回调:
在TaggedTemplateExpression
回调中,我们收集该模板中的所有字符串。例如:
TemplateElement
Literals
收集完成后,还有另一个注册的回调循环遍历收集的类名并确认它们是否存在。
它对集合validClassNames
执行此操作:
而已。
我们马上就知道创建这个验证插件是正确的做法,因为我们实际上在我们的系统以及现有的仪表板代码库中发现了一些拼写错误!
我们创建的最后一个工具是 Visual Studio Code 中的扩展。使用与我们插件中相同的逻辑,ESLint 建议将 typescript 类作为开发人员类型。
这种智能感知使开发人员无需猜测或不得不去 Tailwind 网站搜索并找到正确的类。
正如您在 GIF 中看到的,它不仅建议类名,还显示每个建议的颜色或有用的图标。
借助 Tailwind CSS 和 ESLint,我们已经能够通过改进 DX 来实施我们的标准(可在 Github 内部访问)。