提升前端工程化,携程Design2Code从零到一的实践

时间:2021-12-08 00:39:44

   一、背景

  在软件开发过程中,团队协作效率的提高是我们共同关注的问题。为了解决这一问题,许多团队都开始使用智能化工具。Design2Code(简称D2C)工具是其中一种广受欢迎的选择。

  在本文中,我们将分享D2C工具的核心算法方案设计和实现过程,以及一系列的解决方案。无论你是开发人员,还是设计师,本文都将为你提供有价值的信息。我们希望,通过阅读本文,能帮助你更好地了解D2C工具,并在实际工作中发挥出最大的价值。

   二、前置知识

  2.1 基本概念

  D2C是一种通过使用智能化技术将设计稿转化为代码的工具,旨在提升开发效率,减少人力成本,并缩短设计到开发的流程。通过将设计稿源文件(如:PSD、Sketch、Figma)转化为React、Vue、小程序等平台的前端代码,再使用领域特定语言(DSL)将其转化为各端代码,D2C通常通过人工智能训练的模型或算法实现。

  2.2 哪些特性

  高效协作:使用智能化技术,提升前端工程师和设计师之间的协作效率。

  高还原度:降低设计师检查页面还原度的人力成本。

  高兼容性:减少多端适配的开发成本。

  快速上线:自动生成视图层代码,减少手工工作量。

   三、业界现状

  我们对业内比较出色的D2C产品进行调研,包括阿里 imgcook、京东 Deco、CodeFun、微软 AI Lab 和 Locofy。我们在调研过程中,对各家公司的产品进行了对比,但这里不再赘述。通过调研,我们得出初步结论:

  预装Sketch插件或上传文件解析,导出DSL数据。

  通过 AI 自动处理并生成前端代码,支持使用Web编辑器对代码进行人工干预和编辑。

  需要将设计稿数据存储在对方服务器。

  代码未开源,解决方案也只是简略描述。

  部分公司进阶功能需付费使用。

   四、效果展示

  D2C系统转换流程介绍:

  1. 上传Sketch源文件入口 → 2. 对数据进行处理并返回结果 → 3.展示转换结果。

  通过“查看代码”功能获取多端代码。

  我们对APP、H5 、Online和小程序设计稿进行了还原比对,还原精度达到80%,且在不断提升中。

  下图展示了系统转换效果:

提升前端工程化,携程Design2Code从零到一的实践

   五、解决方案

  5.1 方案分析

  根据上述调研结果以及业务场景,我们的目标是将设计稿转换为代码。主要解决三个问题:

  (1)提取图层信息:需要提取设计图中的图层信息,以获取所有图层元素的位置、大小、形状和颜色等信息。这些信息将为后续的页面布局提供基础。

  (2)信息预处理:在将图层信息转换为代码之前,需要对信息进行一些预处理。例如,筛选和过滤无用信息和图层,处理图层style字段与css的映射关系,解决设计稿中文件夹order如何转换为布局order的问题,以及处理图片资源的导出等。预处理有助于提高后续代码生成过程中的代码质量和布局准确性。

  (3)构建布局关系:利用所提取的图层信息,可以进行精确的页面布局。使页面尽可能地还原设计稿。

  5.2 方案思考

  为了更好的理解问题,将从简单到复杂依次讲解上述三个问题。

  (1)问题1:“提取图层信息”,使用 sketch2json 开源工具可以从 Sketch 和 Figma 设计稿中提取图层信息,将矢量数据转换为 JSON 格式。数据结构中的 'layers' 对应着 HTML 的结构层,而 'style' 对应着 CSS 的表现层。下图展示了从 Sketch 中获取的数据结构。  

提升前端工程化,携程Design2Code从零到一的实践

  (2)问题2:“信息预处理”,需要对基于“提取图层信息”的数据进行一系列处理。这一步的流程较为复杂,涉及到多个技术难点。我们曾经在这一步踩过许多坑,并对技术方案进行了多次调整。其中,有几个技术要点值得着重讲述,例如:

  筛选过滤无用信息和图层:对于 sketch2json 获取的 JSON 数据中,有因 Sketch 的映射关系存在的大量对于图像还原无效的数据字段和因为设计师对于图像绘制不规范产生的无用图层信息,所以需要对其中无效数据字段和无用图层信息做一层数据过滤,减轻 JSON 的量级方便后续计算。

  字段类型映射:瘦身处理后的数据还需要再精细化处理,其中 Sketch 的样式字段等与传统的 CSS 不一致,需要通过转换进行关系映射。对于 Sketch 的图层具体定义为文本还是图片等也需要做相关字段映射。

  图层结构重组:sketch2json 转化后的图层嵌套结构严格依赖视觉稿规范程度,可用性较低,需要对其进行一次结构重组,将所有图层打平,后续利用图层位置信息计算出准确的包含关系。

  Order 层级深度推算:图层打平重组后,如何计算每个图层在DOM Tree中的层叠关系。我们可以根据初始JSON数据中的原始嵌套关系进行推算,为重组后的图层赋予新的层级深度值。

  Symbol 元素处理:在 Sketch 中,Symbol 作为一种特殊元素,创建后可以被重复引用,类似前端中的组件。Symbol 元素在 Sketch 转化后的 JSON 数据中,只包含了其引用ID,它的真实图层数据被保存在了其它位置,需要通过引用ID检索到真实数据后替换 JSON数据中的 Symbol 元素。

  进行系列处理之后,我们得到了前端可用的图层信息,即最终的 DSL 树形数据。

  下图展示了预处理后的 DSL 数据结构:  

提升前端工程化,携程Design2Code从零到一的实践

  (3)问题3:“构建布局关系”是所有步骤中最复杂的一步,因为它涉及到许多技术难点,且几乎没有可供借鉴的开源资料。我们可能需要通过不断的尝试来解决问题。实际上,构建布局关系是基于之前提到的 JSON 数据进行 absolute 和 flex 关系的规整,然后对 DSL 进行递归渲染。具体实现过程可以参阅下文的布局核心算法设计。

  5.3 方案实现

  5.3.1 架构设计  

提升前端工程化,携程Design2Code从零到一的实践

  在进行系统架构设计时,我们综合了上述问题分析和思考后基本确定了技术的可行性和方向。为了满足系统的目标和功能,我们把系统拆分成了三个核心应用,分别负责执行核心任务。这张架构图展示了我们设计的架构,其中包括:视图渲染应用、布局算法服务和切图算法服务三个应用。在下文中,我们将对这些应用进行详细的阐述。

  视图渲染应用:负责渲染转换结果界面。

  通过上传的Sketch文件,我们可以提取出设计稿信息并将其转换为JSON格式。这些信息将被传递给布局算法服务进行处理。算法服务将返回包含图层信息和样式信息的DSL,以树形结构形式呈现。我们将使用DSL来渲染各端页面代码。

  布局算法服务:负责计算元素的位置和布局,以确保界面还原精准。

  具体来说,它会将设计稿的矢量数据转化为前端可用的结构化数据。这个过程包括打平和再加工等主要步骤。打平的目的是将图层之间的关系(父子和兄弟关系)重新组织,再加工的目的是过滤一些干扰图层。最终,算法服务将返回中间层的DSL数据,该数据将用于视图渲染应用的前端代码转换。

  完整流程图:  

提升前端工程化,携程Design2Code从零到一的实践

  切图算法服务:负责将图像切割成合适的尺寸显示在界面上。

  为此,我们使用一台预装了Sketch软件的Mac机器,并使用Sketchtool-cli处理设计稿中的图像、图标和路径。通过接收前端传递的图层symbolID,然后根据symbolID将设计稿中的图片导出并存储在本地磁盘中。接下来,前端会读取本地磁盘中的对应文件夹的图片,并通过接口调用的方式将图片上传到静态资源服务器。最后,服务器会返回可生产访问的CDN URL给前端,前端会将所有URL同步到DSL中。

  另外如何正确合理的对图片进行切割,我们做了如下分类处理:对于sketch里的样式属性利用css不易画出时将这个图层定义为图片背景、对于多种形状结合、蒙层合并的情况,首先判断其当前图层类型、再根据特定算法判断其子图层里的元素是否满足条件进行图层之间的合并,将多个单一图片合并为一整张合理的大图、对于已经采用了三角形、椭圆等特殊形状的图层确立为图片。

  完整流程图:  

提升前端工程化,携程Design2Code从零到一的实践

  5.3.2 核心算法设计

  (1)Sketch层级规律:

  对于Sketch设计稿初始JSON数据中的树状图层结构,每两个图层的层级大小判断存在以下规则:

  若图层节点A是图层节点B的子孙节点,那么,图层A层级 大于 图层B层级;

  若两个图层节点非子孙/祖父节点,那么,这两个节点所在的最小公共子树中,若存在图层A的祖父节点为图层B的祖父节点的右兄弟节点,则表示图层A层级 大于 图层B层级。

  经过分析,图层层级大小和树的先序遍历访问先后顺序一致,即根节点 < 左子树节点 < 右子树节点。  

提升前端工程化,携程Design2Code从零到一的实践

  (2)投影算法:

  布局关系之兄弟关系,利用光影投射的原理,通过从X轴和Y轴的方向对其中的元素进行映射,投影后所在同一个阴影块内的元素,则构成了兄弟关系。兄弟关系算法的示意图:  

提升前端工程化,携程Design2Code从零到一的实践

  (3)交叉算法:

  布局关系之父子关系:通过坐标计算,对于有相交关系的或包含关系的元素之间,则构成了父子关系。父子关系算法示意图:  

提升前端工程化,携程Design2Code从零到一的实践

  另外在父子关系中,还需要考虑元素是否有定位。如果两个元素相交,则需要再次判断元素的大小,以决定父子关系中的父与子。为了方便后续处理布局关系,我们可以为子元素打上绝对定位的标签。

  通过两个元素对角数学关系进行判断:  

提升前端工程化,携程Design2Code从零到一的实践

  (4)flex布局关系推断:

  处理完父子关系和兄弟关系后,为了更好地满足布局的合理性,我们需要通过算法来推测元素中的flex布局方向。  

提升前端工程化,携程Design2Code从零到一的实践

  通过判断子layer,当他们的大小接近,并且Y值相差在固定阈值内且X值相差过大时,可以推断出该层layer的布局使用flex,且direction为row。

  通过判断子layer,当他们的大小接近,并且X值相差在固定阈值内且Y值相差过大时,可以推断出该层layer的布局使用flex,且direction为column。

   六、视觉约束  

提升前端工程化,携程Design2Code从零到一的实践

  为了更高效、准确地还原设计稿,建议输出的 Sketch 源文件做一些规范约束:

  建议将组件保持在独立的画板中,这样可以避免转换无效的元素,方便工程师后续的代码逻辑开发。

  保留有意义的图层,删除无效的空图层,并且尽量避免过深的图层嵌套。这样可以避免渲染树过深,影响页面加载性能。

  图层分组(即 Sketch 中的文件夹)应该合理嵌套,避免交错放置。合理摆放元素文件夹可以有利于还原元素的 DOM 树关系。

  除设计上有必要以外,应尽量避免将同级元素放在容器中交错排列,因为这会导致这些元素在渲染树中被视为父子关系。

  对于相同类型的多行文本,建议使用一个文本图层,这样可以避免因为设计稿中的两个图层而将相同类型的文本转换为两个 HTML 段,从而提高代码复用率,减少代码重复。对于滤镜等特殊效果,建议使用图片来实现,以提高还原精度。

   七、后续规划

  (1)提高布局合理性:

  提高flex弹性布局的推算准确度

  提升dom tree 分割准确度

  减少dom tree 深度

  (2)提高UI还原度:

  列表循环识别能力

  提升长页面还原度能力

  (3)其它:

  减少视觉稿人工干预频次

  适配不同团队设计规范

   八、总结

  D2C技术是一种旨在提高企业产品研发效率,优化设计到开发流程,加速研发进度,以及辅助前端开发人员探索前端智能化道路的技术。主要优势包括:

  探索前端智能化:通过将设计稿转化为前端代码的方式,实现前端智能化。可以提高前端开发的效率,保证设计的精确实现。

  优化产品研发流程:可以提高产品研发的效率,减少人力成本,提升团队的协作效率。更高效地进行产品的迭代和优化。

  简化设计到开发流程:可以优化设计到开发的流程,减少沟通成本,提升工作效率。设计人员可以直接使用设计工具制作设计图,并将其转化为代码,减少设计到开发的翻译过程。

  加速研发进度:可以帮助团队加速研发进度,更快地将产品推向市场,并可以更快速地完成设计和开发工作。同时,也可以更快地进行产品的测试和验证。