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
