当前位置: 首页 > Web前端 > HTML

Deco编辑器高扩展技术架构解析

时间:2023-03-28 14:27:53 HTML

1.后台Deco人工干预页面编辑器是Deco工作流程的重要组成部分。在浏览器中通过智能还原修改输出的Schema,修改后的Schema经过DSL处理后最终下载目标代码。为了赋能业务,打造智能代码生态,Deco编辑器不仅满足常见的静态代码下载场景,还需要针对不同业务方进行定制。这就要求Deco编辑器的架构设计要更加开放。水平需要能够满足二次开发场景。基于以上背景,在设计编辑器架构时主要追求以下目标:编辑器界面可配置,实现定制化开发;第三方组件可实时更新渲染;数据、状态、视图解耦,模块高内聚低耦合;2.业务逻辑2.1业务逻辑分析D2CSchema贯穿整个Deco工作流。Deco编辑器的主要工作是解析Schema生成布局和操作Schema,最后通过Schema生成代码。输入参数:语义处理后的schemajson数据。输出参数:人工干预后的schemajson数据。相关架构介绍请参考揭秘凹凸技术·Deco智能码·开启产研效率革命。2.2业务架构分析Deco编辑器主要由导航状态栏、节点树、渲染画布、样式/属性编辑面板、面板控制栏等组成。核心流程是schema的处理,所以核心模块是节点树+渲染画布+样式/属性编辑面板。节点树和样式/属性编辑面板是相对独立的模块(业务逻辑掺杂较少,大部分是交互逻辑),可以作为独立模块开发。canvas部分涉及布局渲染逻辑,可以作为核心模块开发。导航状态和面板控制需要作为核心模块处理。业务分析完成后,我们对小编的业务模型有了一个初步的了解,而选择合适的技术方案来实现这样的业务模型是非常重要的。3.技术方案设计参考3.1system.js+single-spa微前端框架基于以上对前端业务架构的分析,在设计技术方案时不难立刻想到微前端方案。将编辑器中的各个业务模块拆分成微应用,在workbench的集成环境中使用single-spa管理各个微应用。具有以下特点:同一个页面可以运行不同框架的应用,无需刷新;基于不同框架的前端应用可以独立部署;它支持延迟加载应用内脚本;缺点:应用之间的状态管理比较困难,需要自己实现一个状态管理机制;Deco编辑器没有多应用程序要求。兼容性指数:★★3.2AngularAngular是一个成熟的组件模块管理的前端框架。具有以下特点:内置模块管理功能,可以将不同的功能模块打包成一个模块;内置依赖注入功能,可以将功能模块注入到应用程序中;缺点:学习曲线陡峭,对新加入项目的同学不友好;加载第三方组件比较复杂;适配指数:★★★3.3React+theiawidget+inversify.js使用依赖注入框架inversify,对不同的ReactWidget进行注入,每个Widget可以独立发送数据包。Widget的写法参考theia浏览器widget的写法,具有以下特点:Widget表示一个功能模块,如属性编辑模块、样式编辑模块;Widget有自己的生命周期,比如加载和卸载时对应的hook处理方法;通过WidgetManager统一管理所有的Widget;Widgets相互独立,可扩展性强;缺点:与传统的组件构建方式有很大区别,具有挑战性;API多且复杂,上手不易;兼容性指数:★★★★3.4React+inversify.js+mobx+全局插件组件加载使用inversify注入不同的插件组件,每个插件组件独立封装,使用mobx管理全局状态和状态分布。插件组件的使用有以下特点:插件组件独立开发,可以通过配置文件异步加载到全局渲染;插件组件可以共享全局的mobx状态,可以通过观察者自动更新;通过ModuleRegistry注册插件,统一管理插件加载;天然契合外部业务组件的加载和渲染方式;缺点:插件开发模式比较复杂,需要不同的服务。兼容指数:★★★★★在设计参考以上技术方案的基础上,最终确定了全局插件化组件方案。整体技术栈如下:DescriptionNameFeatures前端渲染React目前支持动态加载模块Modulemanagementinversify.jsdependencyinjection,独立模块可注入各类Servicestatemanagementmobx.jsobservableobjects自动绑定组件更新样式处理postcss/sass原生css预处理包管理lerna好办monorepo开发工具vite基于ES6模块加载模块,极速HMR思想:构建核心Component模块和面板控制通用框架,独立模块可动态注入渲染异步拉取模块配置文件,通过配置渲染面板,动态加载面板内容独立模块独立开发,业务组件(大促/夸克)可以使用lernaLoad作为独立模块进行管理,使用依赖注入管理各个业务模块,去耦数据,状态和视图4.技术架构设计基于以上确定的技术方案和思路,编辑器的技术架构主要分为以下模块:window下:Container是管理各种类实例的容器,可以通过Container.get()方法获取Container中的类实例。通过inversify.js的依赖注入特性,我们将HistoryManager和DataCenter注入到CoreStore中,注册模块时使用单例模式。CoreStore或Container中引用的HistoryManager和DataCenter会指向同一个实例,这对保证整个应用的状态一致性很重要。4.1ModuleRegistryModuleRegistry用于注册editor、Nav、Panels等各个容器,其主要工作是管理容器(加载、卸载、切换面板等)。workbench主要分为Nav容器、Left容器、Main容器、Panels容器:每个容器都承载了对应的前端模块,我们设计了一个模块配置文件module-manifest.json,用于在里面加载对应的js每个容器模块文件:{"version":"0.0.1","name":"deco.workbench","modules":{"nav":{"version":"0.0.1","key":“deco.workbench.nav”,“文件”:{“js”:[“http://dev.jd.com:3000/nav/dist/nav.umd.js”],“css”:[“http://dev.jd.com:3000/nav/dist/style.css"]},},"left":{"version":"0.0.1","key":"deco.workbench.layoute-tree","files":{"js":["http://dev.jd.com:3000/layout-tree/dist/layout-tree.umd.js"],"css":["http://dev.jd.com:3000/layout-tree/dist/style.css"]}}}}ModuleRegistry处理流程如下:4.2CoreStoreCoreStore用于管理整个应用的状态,包括NodeTree、History(历史记载)等。其主要业务逻辑分为以下几点:获取D2CSchema,将Schema转化为Node结构树,通过修改、增删改查等操作生成新的Node结构树,推送最新的Node结构树到CoreStore并注入它。History实例保存Node结构树生成新的D2CSchema获取最新的D2CSchema下载代码CoreStore从Container中注入HistoryManager和DataCenter实例,一般使用方法为:import{injectable,inject}from'inversify'import{Context,ContextData}from'./context'import{HistoryManager}from'./history'import{Schema,TYPE}from'../types'typeHistoryData={nodeTree:Schema,context:ContextData}@injectable()//声明可注入模块classStore{/***history*/privatehistory:HistoryManager/***contextdata(datacenter)*/privatecontext:Contextconstructor(//dependencyinjection@inject(TYPE.HISTORY_MANAGER)history:HistoryManager,@inject(TYPE.DATA_CONTEXT)context:Context){this.history=historythis.context=context}}在上面的代码块中,history和datacenter作为独立的模块注入到CoreStore中,中对应的修改这里的stance会影响到Container下的实例对象,因为它们都指向同一个实例。4.3HistoryManagerHistoryManager主要用于管理用户操作历史信息。基于依赖注入特性,可以直接注入到CoreStore中使用,也可以通过Container.get()方法获取最新的实例。HistoryManager是一个双向链表结构的抽象类。通过对每个链表节点保存数据快照,方便快捷地穿梭历史记录。与普通双向链表不同的是,当一个节点被插入到History链表中时,之前的链表节点会重新链接一个新的分支。4.4DataCenter是整个Deco编辑器用来管理楼层数据的一个独立模块。一开始只是用来服务于编辑器本身的应用开发。后来为了方便用户在编辑器应用中进行调试,正式采用数据中心作为落户的功能方式。楼层数据是页面节点在进行数据绑定时使用的真实数据,通过当前节点的数据上下文获取。如果把这些真实的数据绑定到原来的NodeTree上,那么我们的NodeTree就是一个存储所有信息的节点树,逻辑相当复杂冗余,而且要做Schema同步也是一件极其困难的事情。因此,我们考虑将楼层数据单独提取到一个模块中进行管理。如下图,ContextTree是数据上下文的数据节点树,它和NodeTree上的节点一个一个绑定,通过位置信息(比如0-0,代表第一个子节点)绑定在一起根节点),和NodeTree的区别在于它是一个有空间关系的节点树。例如,需要将位置0-2的节点插入到上下文节点中,则需要将位置0-2的上下文节点插入到位置0的子节点中。同时,设置上下文节点其position是0-2-0作为0-2节点的子节点。同样,如果从ContextTree中删除0-2节点,则需要从0节点的子节点中删除0-2节点,并将0-2-0节点设置为0节点的子节点。这样一来,数据管理模块从NodeTree中分离出来,DataCenter独立管理页面的数据上下文,不仅让我们在代码层面实现了更多的解耦,也沉淀了“数据中心”功能模块。数据绑定时方便用户调试。5技术难点5.1模块管理5.1.1Inversify通过上面的架构分析不难看出,虽然Deco编辑器的主要业务功能逻辑比较简单,但是各个模块相互独立,相互配合完成编辑器应用数据,state,history,renderingupdate的操作如果单纯的用ES6Module的模块来管理是远远不够的。因此,我们引入了inversify.js来进行模块依赖注入管理。inversify是一个IoC(InversionofControl,控制反转)库,它是AOP(AspectOrientedProgramming,面向方面编程)的JavaScript实现。编辑器使用“Singleton”单例模式,每次从容器中获取类时都是同一个实例。无论是从类中的依赖中获取实例还是从全局Container中获取实例都是一样的,这个特性为整个编辑器应用状态的一致性提供了强有力的保证。AOP的天然优势是模块解耦,一定程度上提高了编辑器应用的可扩展性。更多关于AOP和IoC的介绍可以参考文章玲珑SNS服务AOP和IoC实践。5.1.2mobx得益于mobx观察者模式的状态更新机制,使得状态管理和视图更新更加解耦,为编辑器状态维护和模块管理提供了极大的便利。不同的数据状态(如AppStore和UserStore)相互独立,互不干扰。5.2页面节点树的查找和更新页面节点树(NodeTree)是一种为Schema设计的抽象树。它的主要功能是对页面节点进行增删改查,同时也映射到渲染模块更新页面画布Render,最后通过一个转换方法转换为Schema。NodeTree是页面节点的抽象表示。当页面设计稿比较大时(比如宣传设计稿),节点树也是一个非常大的抽象树。在搜索节点时,如果使用简单的深度遍历算法进行搜索,将会有巨大的性能损失。针对这种情况,我们获取每个节点的位置信息(比如0-0)进行索引匹配搜索,基本实现了无害搜索。另外,基于React的更新机制,在NodeTree节点增加或删除后,索引会自动更新,省去了手动更新位置信息的麻烦。同时,也是基于节点位置信息的设计,实现了上文介绍的数据上下文节点的空间信息维护。5.3第三方组件的加载和渲染在DecoSmartCode618的应用中,提到了识别Deco组件的过程。在Deco中,一个组件样本(视图)对应一个组件配置。基于组件配置的多样性,一个组件可能有多个样本。对于小编来说,组件识别服务返回的相似组件推荐,实际上返回的是组件的属性配置信息。编辑器只要找到对应的样例组件配置信息,就可以进行相应的替换工作。那么,第三方组件是如何加载的呢?在文章的开头,我们介绍了插件开发模式。对于Deco编辑器来说,第三方组件也是一个插件,所以只需要将第三方组件库打包成UMD格式的JavaScript文件,并在module-manifest中配置deps插件即可.json文件中的信息,使得第三方组件以插件的形式加载到编辑器的全局环境中。同时,编辑器中存储了第三方组件的配置表。当用户更换相似组件时,通过配置表获取对应样本的配置信息,渲染到编辑器的canvas模块。默认规定第三方组件使用React开发,小编在渲染时使用React.createElement原生方法进行组件渲染。//组件配置信息数据结构导出接口AtomComponent{id:stringcomponentName:stringlogicHoc:stringtype:stringimage:stringname:stringprops:anypkg:stringtableName:stringvalue?:string|孩子数量?:(部分|字符串)[]|stringpropsComponent?:Partial[]}目前在代码中封装了这个配置表。在以后的编辑器版本中,这个配置表会和Deco开放平台整合,开放给用户编辑。编辑器初始加载时,会以第三方配置的形式加载。6最后,目前Deco已经支持6.18和11.11背景下的场馆开发,并开放了内部低代码平台,可以一键构建代码和页面预览。德科承建的数十层楼成功上线,效率提升48%。%。Deco智能码项目是O2MLabs在“前端智能”方向的探索。我们尝试从设计稿开始到生成代码(DesignToCode),完成现有的设计到研发。提高产学研效率。其中,大量的算法和AI能力被用来实现对设计稿的分析和识别。欢迎感兴趣的童鞋关注我们的账号“凹凸实验室”(知乎、掘金)。7更文设计稿一键生成代码,研发智能探索实践,助力双11个性化场馆高效交付:德科智能代码技术揭秘机器学习超基础入门-原理