
TL; DR
使用Node JS中的自定义构建脚本,可以操纵一系列Sketch文件,然后使用内部Sketch工具自动导出其资产,以生成支持多个平台和不同品牌,针对多个平台和不同品牌的多个图标库通过设计令牌对资产进行着色,以及通过命名约定对资产进行AB测试。 简单容易:)
好吧,实际上并不是那么容易,但是可以肯定的做到。 这篇文章详细说明了我们是如何做到的,以及在此过程中我们发现了什么。
我们试图解决的问题
在
Badoo,我们构建了一个约会应用程序。 实际上,有多个约会应用程序。 对于跨
多个团队的多个平台(
iOS ,
Android ,
移动Web ,
桌面Web )。
我们在应用程序中使用了数百个图标。 其中一些在不同的应用程序中是相同的,而某些特定于应用程序所反映的品牌。 图标与设计的演变同步不断发展。 有时会添加全新的图标,而其他图标会被更新,而另一些图标会被删除(尽管它们通常仍保留在代码库中)。
我们的设计团队设计和维护图标,直到现在,它们向不同的团队,平台和应用程序提供正确资产的唯一方法是通过电子邮件,聊天或投递箱发送图标。 这不仅耗时,而且几乎总是容易出错。 实际上,我们发现每次都会发生错误(我们是人类!):图标会在一个平台上更新,而不会在另一个平台上更新; 或图标丢失或格式或大小错误。 因此,设计师和开发人员之间经常来回走动。 开发人员可以直接从Sketch文件中导出图标,然后将这些图标添加到代码库中,但无需检查是否已经存在类似的图标(可重复使用)。 我确定您知道我在说什么。
在Badoo,我们有一个
名为Cosmos的
设计系统,并且最近我们为主应用程序及其白标引入了跨多个平台(移动Web,Android和iOS)
的设计令牌库 。 本质上,我们现在可以使用基本设计值来传达设计决策(例如按钮的边框,特定功能页面的背景颜色,标题1的字体大小或弹出动画的持续时间),所有这些都将自动处理并交付给所有应用程序,以及所有在其应用程序中使用这些设计令牌的平台。
现在,我们如何能够将设计理念(例如更改颜色)转变为生产中的真实代码,只需单击几下即可,几乎几乎没有时间,这确实给产品经理和设计师留下了深刻的印象。
因此,他们的下一个问题(和要求)是:您可以为资产做类似的事情吗? 我们的答案是:是的,我们(可能)可以!
我必须承认,那是当时的信仰飞跃。 我们对如何执行操作有一些想法,但是我们完全不确定它在技术上是否可行,并且我们会受到所有限制。 我们同意从MVP项目开始,但是到最后,一切都进行得非常顺利,它成为了我们的最终产品,具有所有必要的功能。
要求
MVP的要求非常明确:创建一个可以接收Sketch文件的管道,并以不同的格式针对不同的平台导出文件中包含的所有图标,并且每个图标都适用于AB测试。
这很复杂,因为在我们的产品中,一个图标可以针对不同的品牌/白色标签具有多种不同的颜色和/或不同的形状(尽管该应用的代码库以及该图标的名称是相同的)。
查看我们的应用程序中使用的一些图标,您会注意到其中一些是相同的,一些彼此非常相似,但有一些细节,而另一些在形状和颜色上却大不相同:
不同品牌的图标比较现在,图标中使用的颜色不仅是纯色,而且与该品牌及其特定功能的
设计令牌中所述的确切颜色相匹配:
比较不同品牌的颜色。 颜色值被指定为设计标记。因此,我们使用这一新资产管道的目标不仅是针对所有不同的平台和品牌,使图标的生成和交付过程自动化,而且能够根据品牌/白色为图标“动态”着色标签。
素描和素描工具
Sketch是我们设计团队使用的主要设计工具。 即使我们确实考虑了其他选项(主要是
Figma ),我们也知道Sketch是我们将用于该项目的源文件的格式(仅仅是因为它是我们的设计人员更精通的工具,而且它是格式使用现有图标/素材资源的文件中的其他原因)。
事实是,在项目开始时,我们甚至不确定平台期望的最终格式。 在我们看来,该过程将是非常基本的:从Sketch文件中以SVG格式导出图标,然后在Mobile Web和Android中使用SVG文件,对于iOS,找到一个可以将SVG转换为PDF的库。 就是这样。 那是我们开始时的计划,尽管我们不知道它是否会起作用,也不知道我们可能会遇到的未知未知数(因此,MVP会检查它是否可行,如果可以的话,还要付出多少努力)
我不知道您是否曾经使用过“ PDF转换器”,但根据我的经验,它们通常很痛苦。 他们“几乎”完成了工作,但从未达到您真正需要的100%。 因此,在我的脑海中,我感到我们正在走一条危险的道路。
Sketch具有非常完美的导出资源的方式,我从来没有遇到过问题(无论是SVG,PDF还是其他格式)。 因此,我想看看是否还有其他与Sketch互动的方式,可以使用其引擎通过Sketch直接导出资产,可能是以编程方式进行的(我想知道是否可以构建自定义插件,尽管那意味着为我做了很多工作,不仅因为我在该领域的经验为零!)。
我知道Sketch在内部只不过是一个zip文件(如果将
.sketch文件重命名为
.zip ,请双击以解压缩它,然后打开生成的文件夹,您会看到JSON文件列表以及用作预览):
草图文件的内部结构,一旦解压缩因此,我开始探索不同的JSON文件,试图了解它们之间的连接和依赖性。
我意识到,尽管JSON文件被深深地嵌套了(而且很大!),但它们对象内部不同实体之间的关系并不太复杂:您拥有页面,画板和图层;它们具有不同的样式。 在图层内部,您具有路径,并且可以在它们之间共享样式; 这些实体中的每个实体都有一个唯一的ID,该ID用于在不同文件之间保留引用。 并且所有“页面”对象都保存在JSON文件中,并存储在一个名为
pages的子文件夹中,该页面的ID用作文件名。
我在探索过程中发现的一个重要发现是,
图层,页面和样式的名称只是标签,可以随时更改它们,而不会影响Sketch文件的内部工作。 重要的是分配给他们的唯一ID,并且永远不会暴露给最终用户(尽管可以在JSON文件中读取和引用)。 这是样式的唯一ID的示例:
{ "_class": "sharedStyle", "do_objectID": "49BA4E98-8D63-435C-81D9-E2F6CDB63136", "name": "name-of/the-style", "value": { "_class": "style", "endMarkerType": 0, "fills": [ { "_class": "fill", "isEnabled": true, "color": { "_class": "color", "alpha": 1, "blue": 0.7176470588235294, "green": 0.4627450980392159, "red": 0 }, "fillType": 0, "noiseIndex": 0, "noiseIntensity": 0, "patternFillType": 1, "patternTileScale": 1 } ], "miterLimit": 10, "startMarkerType": 0, "windingRule": 1 } }
这给了我一个主意:也许我们可以在画板和页面的名称上使用特定的约定,以声明有关不同资产之间关系的某种元信息,并在构建时以编程方式使用它们。
素描工具
至此,在初步探索结束时,该计划已从
“让我们在SVG中导出图标,然后将其转换”更改为
“让我们构建一个插件,在Sketch中,我们可以直接在最终图标中导出图标”。格式“ 。 但是即使那样,该计划仍然非常模糊(技术可行性仍然不确定)。
在查看现有插件(尤其是其源代码)以查看它们是否以及如何与Sketch Export API交互时,我遇到了一个以前从未听说过的工具:Sketchtool。
Sketchtool是官方的Sketch工具(正式名称:由Bohemian Coding开发),
根据文档 ,该工具为:
...是与Sketch捆绑在一起的命令行实用程序,可让您对Sketch文档执行某些操作,例如检查它们或导出资产。 它还使您可以从命令行控制Sketch来执行一些操作(例如,运行插件)。
挂...
命令行实用程序来执行诸如
导出资产之类的操作? 就是我要找的东西! 此外,作为一种官方工具,不会出现任何版本,过时,维护等问题。
我立即开始研究它,并阅读了文档,并逐渐在Sketch网站上只浏览
了一页 (我几乎找不到其他资源或页面,因此我从未听说过这是可以理解的它)
Sketchtool直接与Sketch捆绑在一起,您可以在以下路径的Sketch中找到它:
Sketch.app/Contents/Resources/sketchtool/
在CLI中使用以下命令启动它时:
$ /Applications/Sketch.app/Contents/Resources/sketchtool/bin/sketchtool
这是您在终端上看到的输出(我已经简化了一点):
Usage: sketchtool <command> [<args>] [--formats=<string>] [--use-id-for-name{=YES|NO}] [--export-page-as-fallback{=YES|NO}] [--serial{=YES|NO}] [--context=<string>] [--application=<path>] [--without-activating{=YES|NO}] [--item=<string>] [--items=<string>] [--safemode{=YES|NO} | --no-safemode | -S {<YES|NO>}] [--max-size=<float> | -m <float>] [--background=<string> | -g <string>] [--compression=<float> | -c <float>] [--new-instance{=YES|NO}] [--reveal{=YES|NO}] [--timeout=<float>] [--include-symbols{=YES|NO}] [--bounds=<rectangle>] [--outputJSON=<path>] [--filename=<string>] [--wait-for-exit{=YES|NO}] [--scales=<path>] [--overwriting{=YES|NO}] [--group-contents-only{=YES|NO}] [--trimmed{=YES|NO}] [--help] [--progressive{=YES|NO}] [--save-for-web{=YES|NO}] [--output=<path>] Commands: dump Dump out the structure of a document as JSON. export artboards Export one or more artboards export layers Export one or more layers export pages Export an area from one or more pages export preview Export a preview image for a document export slices Export one or more slices help Show this help message. list artboards List information on the document's artboards. list formats List the supported export formats. list layers List information on all of the document's layers. list pages List information on the document's pages. list slices List information on the document's slices. metadata List the metadata for a document. run Run a command from a plugin, inside Sketch. show Show the location of the various sketch folders. See 'sketchtool help <command>' for more information on a specific command.
如您所见,该工具具有四个主要功能:
读取/转储内部JSON文件的元数据;
列出文件
中的实体;
出口这些实体; 并
运行插件公开的命令。 此外,每个命令都有很多可用的
选项 。 对于导出命令,几乎所有在
导出面板中找到的选项都可以通过Sketchtool的命令行使用:
Sketch中的“导出”面板,带有可用选项这意味着Sketch可以通过
sketchtool直接用作导出“引擎”,而无需外部转换器(例如,从SVG到PNG或PDF)。 大事了!
使用
sketchtool和一个带有几个图标的简单Sketch文件进行的快速测试确认了所有最初的假设:仅通过使用此简单工具,我们就可以避免使用第三方导出器和构建自己的自定义导出器:Sketch可以完成所有工作!
草图文件
一旦我们知道Sketch是我们将要使用的用于存储和导出图标的工具,就可以将应用程序中使用的图标实际收集到Sketch文件中了。
最初,我们只计划使用有限的图标集(用于MVP项目的图标集),但是我们很快意识到最好一次收集所有图标集,以便能够立即发现重复项,不一致之处,任何遗漏,等
我们的设计师完成了一项令人难以置信的工作,在短短几天之内,他们的Sketch文件中使用的大部分资产便被收集并整理成一个文件。 此时,Sketch文件如下所示:
Sketch文件概述,其中包含我们的应用程序中使用的图标。在文件中,每个图标都有自己的画板,并用所需的图标名称命名(后来在导出资源时,Sketch将其用作文件名)。
将所有路径转换为轮廓,并将组合的路径(通常作为
并集或
减法 )展平为单个形状。 这样可以确保生成的资产保持其在源文件中的完美视觉外观,并与各种平台保持最佳兼容性。
资产草图文件中图标(及其图标层)的组织方式示例。 应用于画板上的浅粉红色背景与白色区域形成视觉对比。使用共享样式(和设计令牌)为图标动态着色
收集完图标后,下一步就是为它们应用正确的颜色。 我们要做的是
在Sketch中创建一组预定义的
共享样式 ,其名称与我们
设计系统中使用的
设计标记的名称匹配
,然后使用它们将颜色应用于图标。
这是将样式应用于图层的方式:
Sketch中具有预定义样式(填充颜色)的图层。这是声明样式并将其应用于元素的方式:
我们如何决定在Sketch中组织样式此处的命名约定非常重要。 设计师可以在任何子文件夹中组织样式,只要样式名称本身与该颜色的相应设计标记的名称匹配即可。 因此,以后可以由构建脚本以编程方式引用它。
用于AB测试的页面和画板名称
此时,是时候了解如何确保设计人员能够对图标进行AB测试了。 再次,最终,我们决定依赖命名约定(这里是KISS的忠实拥护者)。
在这种情况下,我们使用
页面名称来检测一组图标何时是AB测试/实验(使用“
XP_”作为前缀),使用
画板名称来检测AB测试所指的资产及其不同的变体(括在方括号内)。
页面和画板上的命名约定如何用于“声明” AB测试。 注意:这些图标仅仅是为测试目的而创建的示例,它们不是产品中使用的真实图标 :)
用于测试和选项的名称不是通用名称:它们必须与在内部用户拆分工具中分配给实验/选项的
唯一名称ID匹配。 这样,资产可以在以后与正确的AB测试用户组正确关联。
多个品牌的多个文件
最后一个难题是:我们如何为不同品牌支持同一图标的不同形状?
对于产品经理来说 ,这是
非常重要的要求 ,并且我们有多种选择可供使用。 首先,我们考虑在同一Sketch文件中使用不同的页面,每个品牌使用不同的页面名称; 但是很快我们意识到,这会使设计师使图标在不同品牌之间保持同步变得更加复杂和困难。 因此,我们得出结论,解决方案是拥有多个文件:一个
“通用”文件 ,其中存储了不同品牌相同的所有图标,以及
针对品牌的特定于文件的文件 ,
这些文件 覆盖了通用中的“基本”图标文件。

此时,草图文件已准备就绪。 我们准备开始编写代码。
待续。