共计 5550 个字符,预计需要花费 14 分钟才能阅读完成。
简介:低代码渲染是什么? 在理解低代码渲染之前,咱们先来理解一下低代码渲染是什么?首先,咱们来考虑一下,低代码是什么?比方下图阿里外部的某低代码平台,阿里对外的低代码产品有宜搭。他们都是通过可视化,即拖拽、配置,再加上很少的代码来设计出页面。
640 (11).png
咱们能够看到它的源码是一份 json 文件,这份 json 文件相当于是一份新的语言,浏览器是没有方法进行辨认的,所以咱们须要低代码渲染引擎将 json 渲染到浏览器中。
低代码如何渲染?
正如烹饪一样,为了做胜利一份美食,咱们须要菜谱和食材,而后通过不同的解决形式,比方煎、炒、炸等烹饪形式做进去一道菜。
image.png
咱们的低代码渲染也是有相似的公式:
image.png
其中菜谱咱们能够认为这是一份规范,它保障了同样一道菜在不同中央 80% 以上的口味都是统一的。如果短少了这份规范,很有可能在不同的中央吃到的宫保鸡丁滋味、食材等都齐全不一样。
而低代码相干的协定就是低代码渲染的规范,如果低代码渲染都依照这一份规范来做,能够让不同部门、团队、公司低代码解析都是统一的。这样能够不便物料、工具集等生态产物进行无障碍流通。
协定也能够了解为是 React/Vue 等 ProCode 代码和低代码 json 源码如何相互解析的阐明
咱们的协定有两份:
《低代码引擎搭建协定标准》
《低代码引擎资产包协定标准》
这里咱们对渲染所需的几个要害的协定字段做一下介绍。
协定原文:https://lowcode-engine.cn/low…
《低代码引擎搭建协定标准》
componentsMap
它形容的是页面用到的组件的信息,例如从 ProCode 转化为咱们的 json 协定内容如图:
image.png
destructuring 为 true 示意咱们用解构的形式来获取组件。当然咱们还有其余的形容字段来保障能反对各种组件的导出形式。
image.png
utils
它形容的是页面应用到的工具类扩大信息,比方咱们页面中想应用 lodash.clone 办法,那么就须要在协定中这样形容:
image.png
componentsTree
componentsTree 形容的是页面的组件树,次要形容的内容相当于咱们写的 JSX:
image.png
image.png
《低代码引擎资产包协定标准》
搭建协定中尽管形容了组件的起源,然而咱们在浏览器运行时中无奈应用 npm 引入,所以咱们还须要资产包协定,来帮忙咱们获取组件、工具集等渲染所需资料。
packages
image.png
上图是 packages 的一个示例,它形容了一个组件的 urls。当咱们渲染的时候,须要在浏览器中加载上述的 urls。
加载之后,咱们能够通过 window.Next.Button 获取到 Button 组件,如下图所示。
image.png
大家能够在 https://lowcode-engine.cn/demo 中尝试看看咱们加载了多少组件。
资料
schema
咱们在设计器中进行可视化拖拽、配置实际上就是产生咱们的 schema。这份 schema 就是遵循《低代码引擎搭建协定标准》的产物,每一个页面对应一个 schema。
640 (12).png
页面资产包
依据资产包协定标准,咱们须要提供一份页面 / 利用的资产包信息。
在阿里外部的低代码产品中的某低代码平台外面,有一个依赖治理页面,在这里咱们能够新增组件,在新增组件之后进行打包构建。
640 (13).png
咱们能够看到依赖配置信息中实际上是没有配置 urls 的,只是配置 package、version 等信息。
当咱们点击打包构建时,咱们会通过 package、version 等信息,将其打包成 UMD 资源,作为资产包中的 urls。
image.png
而这份 urls 会依据 package、version 进行存储并缓存,所以当咱们新公布了一份 npm 包,并且进行打包构建的时候,打包构建的工夫会比拟长,而在第二个我的项目外面再增加一次,就很快了,这就是因为有了缓存,大大减少了打包构建工夫。
组件和工具扩大
咱们通过搭建协定中 componentsMap 的形容信息,能够晓得 Button 组件是在 @alifd/next 中。
image.png
而通过资产包协定的 package 信息,咱们就能够晓得如何获取到 @alifd/next 内容,也就晓得 Button 组件如何获取了。
image.png
通过这种形式,咱们就能够获取到页面的 components 和 utils。
image.png
其余
咱们还须要依据咱们应用的技术栈,在 html 中提前加载 react/rax 相干依赖的资源。
image.png
如果是图表组件咱们也须要加载 highcharts 资源。
image.png
渲染形式
渲染形式次要有两个大类:
出码渲染
运行时渲染
其中在阿里外部大多数低代码平台中,咱们次要应用的都是运行时渲染,包含宜搭低代码产品,只有少部分对性能要求较高的产品才会应用出码渲染的形式。
image.png
出码渲染是将 schema 转化为 Vue 源码、React 源码或者其余语言的源码。当然就像 React 工程须要进行打包构建能力在浏览器中渲染一样,咱们会将 React/ 其余源码进行打包,打包成一份 Bundle 文件,之后就能够在浏览器中进行生产,渲染出页面了。
以上的过程大多数都是在构建服务中进行的,而 Bundle 渲染为页面是在浏览器中实现的,这一部分自身都是依赖市面上成熟的前端框架,比方 React、Vue 等,所以这时候在浏览器的运行时曾经不存在低代码渲染了。
上面是某个页面的 schema 转化为 React ProCode 的示例:
640 (14).png
这里对出码渲染就不做过多的介绍了,有趣味的小伙伴能够去看看低代码引擎中的出码模块。
运行时渲染
运行时渲染和出码渲染的次要区别在于,页面 schema 渲染成页面都是在浏览器中实现的,不存在预编译的过程。
image.png
运行时渲染详解
这里咱们就运行时渲染进行具体的介绍。
渲染能力概览
渲染能力就是咱们依据协定的内容,在运行时渲染引擎上反对的能力。
640 (15).png
比方咱们要渲染的一个页面,能够把它解析成一个树状构造,而其中的最底层的节点就是咱们最小粒度的组件。
对于这个组件,咱们须要反对的能力次要是:
1) 获取源码组件
2) 解析组件的 props
3) 获取组件的 children
4) 保留并传入上下文,包含循环上下文,插槽上下文等;
5) 节点更新,当参数变动时须要更新对应的节点
6) 节点循环解决
7) 获取节点实例并进行存储
……
而比组件更大的一个纬度来说,也就是页面的渲染,而他们的能力须要:
1) 页面生命周期的生成和执行;
2) 页面内组件树形容生成,并递归解决单个组件;
3) 页面上下文生成,比方数据源 State、低代码组件的 Props 等。
4) 页面 API 反对;
……
组件渲染
获取源码组件
通过 Node 的 componentName 和之前获取到的 components 就能够获取到 React/Rax 的源码组件。下面的渲染所需资料获取的模块曾经介绍过了。
解析 props
为了实现所有的搭建场景,咱们的 props 有几种解析形式:
1. 参数是确定的值
配置的值是确定的,比方确定的 text 文本。
image.png
2. 参数是须要计算的表达式
配置的值依据数据源进行变动的,比如说 text 文件须要依据 state.text 进行计算的场景。
这里会用 type:JSExpression 来形容须要计算的表达式。
image.png
3. 参数是函数
参数是作为函数传到组件中,比如说 Button 组件配置的 onClick 事件、onChange 事件等。
这里会用 type:JSFunction 来形容函数。
image.png
4. 参数是 React/ 其余框架的节点
协定中还形容了某一种属性作为 ReactNode 渲染的状况,这时候组件渲染的内容不是 children,而是这个组件的某一个参数。
其中 type 为 JSSlot 就是形容这种状况的参数格局。
image.png
下面代码中的 Card 中的 this.props.title 在 React 渲染引擎下就会解析成 ReactNode。
获取组件的 children
通过递归解决即可获取其 children,下图是其伪代码。
image.png
解决节点更新机制
当数据源变动的时候,咱们须要对页面进行更新,次要有两种更新形式,全量更新和增量更新。
640 (16).png
1、全量更新
全量更新就是只有数据源发生变化,咱们就从页面的顶层节点,也就是 Page 开始从头开始再次进行计算、递归子元素并对 props 进行计算。也就是每一个节点都会从新计算和渲染。
这样的益处的是解决比较简单,而害处就是因为多了不必要的计算和渲染,在性能上较差,特地是如果节点比拟多就会呈现显著的卡顿。
2、增量更新
增量更新是找到用到这个数据源的组件才进行更新,也就是上图中的 TextA 和 TextC。
咱们实现的形式就是利用了 mobx,如下图所示咱们将 state 和 props 进行 observable。并对每一个组件都进行 observer 观测,当组件用到的 state 或者 props 产生变动的时候,mobx 会管制其进行更新。
image.png
解决节点循环
因为在循环的场景中,循环的组件和其子组件须要通过 this.item 和 this.index 来获取循环的索引和循环的值。
所以咱们在节点循环的时候,咱们须要计算循环的值,并将循环的值,作为以后节点和节点的 children 的 scope 来解析。
解决节点实例
当咱们配置了组件的 ref,咱们就能够通过 this.$(ref) 来获取组件实例。
在 React 中,咱们次要是间接利用组件的 ref 参数,来获取到组件的实例,并将其存储到渲染引擎的上下文中。
页面渲染
执行页面生命周期
在搭建协定中,定义的生命周期办法次要是 React16 的规范生命周期办法,对于 React 的渲染引擎来说,只须要在适合的机会调用相干生命周期办法即可。
而对于其余语言的渲染引擎,咱们就须要依据状况,在其相似的生命周期中调用 schema 中的生命周期办法。比方 Rax 技术栈的渲染引擎,因为没有相似的生命周期,所以应用 hooks 来代替对应的生命周期;当然对于使用者来说是感知不到差异的。
递归解析组件树
上面是其递归组件树示例的一个伪代码。
image.png
而在递归之后,咱们就能够依照组件的渲染逻辑,对单个组件进行渲染了。
递归解决组件,依照前文提到的组件渲染相干的逻辑对每一个组件进行解决。就能够依照组件树的层级关系将其绘制到浏览器上。
页面上下文生成
上下文、状态和数据管理和层级以及包裹的组件是有关系的,其中页面下的组件,应用的是页面的上下文、数据和状态。在页面包裹的区块下的组件,优先应用区块下的上下文、状态和数据,如果区块中不存在,这时会去页面上下文、状态和数据中寻找。
image.png
上下文、状态和数据管理应用的是 proto 来实现的。当进入区块时,会新建区块数据和区块上下文,并应用 proto 来继承页面上下文和页面数据,这样就能够在区块中优先应用区块的数据和上下文,当区块中没有的时候,会向页面数据和上下文中查找。整体逻辑相似上面的伪代码:
image.png
image.png
输入后果如下:
image.png
实现上述的几个逻辑,就能够实现一个最简略的运行时低代码渲染引擎了。
image.png
目前我这边保护的运行时渲染框架次要有三套:
lowcode-react-renderer 和 lowcode-rax-renderer:是低代码引擎(lowcode-engine)提供的低代码运行时渲染能力,其底层应用的是 renderer-core。
Render-Engine:是团体外部的基于 React 运行时的低代码渲染引擎,反对利用级别的渲染,包含导航、登陆等利用级别的渲染能力。
Rax-Engine:也是利用级别的渲染能力,运行时框架依赖的是 Rax。
痛点 - 保护老本高
image.png
咱们的运行时渲染框架有独立的三套,而自身运行时的是有很多能力是通用的,是能够进一步上层复用,Renderer-Core 就是对通用的运行时渲染能力进行了上层,而 React 渲染器和 Rax 渲染器只须要针对差别局部进行适配。
解决方案
而三套独立的运行时渲染框架导致咱们的保护老本是大于 3 的。基于这个起因,在后续的迭代中咱们会将通用能力上层,而他们之间的差别能力通过插件化来适配。
image.png
痛点 - 调试艰难这个痛点是来自低代码平台的使用者。
image.png
大多数看到这个问题的就是利用的开发人员,然而就算是开发人员,当遇到这个报错了也还是比拟懵逼的,无从下手。这导致低代码平台的答疑老本始终比拟高,而低代码使用者在应用低代码平台的时候体验也会很差。
另外当遇到这个报错时,只有应用浏览器调试能力解决问题,这就导致了低代码研发人员必须要有一部分的前端研发能力,导致低代码产品的应用人群无奈进一步扩充。
解决方案
通过研发低代码渲染调试能力,来帮忙低代码平台的应用着解决相干问题。相干解决方案行将在掘金大会上进行线上直播分享,主题是《基于 LowCodeEngine 调试能力建设与实际》
将来布局
最初咱们的运行时渲染体系架构最终会实现成这样。
image.png 在低代码引擎标准协议的根底上,将运行时的通用逻辑进行下沉到 Renderer-Core 中,并基于它实现 React 渲染器和 Rax 渲染器。其余差异性的运行时渲染能力比方画布渲染、利用渲染等通过扩大插件来实现。
而在解决方案上会将一部分欠缺低代码调试能力、也会提供服务端渲染能力解决运行时渲染能力的性能瓶颈。
原文链接:http://click.aliyun.com/m/100…
本文为阿里云原创内容,未经容许不得转载。