【低代码漫谈】 lowcode-engine - Vue Renderer 尝试
highlight: vs2015
导读
之前《lowcode-engine 协议浅析》这篇文档分析了 lowcode-engine 的协议,有了一定的收获。但是笔者发现官方只实现了 React 和 Rax 的方案,并没有 Vue 的方案,而笔者周围有很多 Vue 的项目,所以需要深入研究一下 lowcode-engine 的实现原理,甚至源代码,然后尝试实现一下 Vue Renderer。
正文
React Renderer Demo
官网给的 Demo 效果如下(原文有 bug,经过了修复):
可见,lowcode-react-renderer
实际上就是暴露出了一个 ReactRenderer
组件,它接收 schema
和 components
两个属性,然后就能在页面当中渲染出结果了,仅此而已。
为了更能够体现框架无关性,笔者又做了一个纯 JS 语法的 Demo,如下:
虽然理论上知道 jsx 就是 JS,但是这样一些心里还是更踏实了点。既然是框架无关,那下一步就是实现 Vue Renderer 了,在此之前,我们先来看下 React Renderer 的具体实现。
React Renderer 源码
```ts import React, { Component, PureComponent, createElement, createContext, forwardRef, ReactInstance, ContextType } from 'react'; import ReactDOM from 'react-dom'; import { adapter, pageRendererFactory, componentRendererFactory, blockRendererFactory, addonRendererFactory, tempRendererFactory, rendererFactory, types, } from '@alilc/lowcode-renderer-core'; import ConfigProvider from '@alifd/next/lib/config-provider';
window.React = React; (window as any).ReactDom = ReactDOM;
adapter.setRuntime({ Component, PureComponent, createContext, createElement, forwardRef, findDOMNode: ReactDOM.findDOMNode, });
adapter.setRenderers({ PageRenderer: pageRendererFactory(), ComponentRenderer: componentRendererFactory(), BlockRenderer: blockRendererFactory(), AddonRenderer: addonRendererFactory(), TempRenderer: tempRendererFactory(), DivRenderer: blockRendererFactory(), });
adapter.setConfigProvider(ConfigProvider);
function factory(): types.IRenderComponent { const Renderer = rendererFactory(); return class ReactRenderer extends Renderer implements Component { readonly props: types.IRendererProps;
context: ContextType<any>;
setState: (
state: types.IRendererState,
callback?: () => void,
) => void;
forceUpdate: (callback?: () => void) => void;
refs: {
[key: string]: ReactInstance;
};
constructor(props: types.IRendererProps, context: ContextType<any>) {
super(props, context);
}
isValidComponent(obj: any) {
return obj?.prototype?.isReactComponent || obj?.prototype instanceof Component;
}
}; }
export default factory(); ``` 没错,源码就这些,不到 70 行。Rax Renderer 的源码能稍微多一点,所有 5 个文件加起来 200 多行。很惊讶,很神奇对吗。这是怎么做到的呢?这是不是意味着实现 Vue Renderer 也可以很简单呢?
初看这部分代码就做了两件事:
1. 用 adapter
注入了很多方法,主要分为 setRuntime
、setRenderers
和 setConfigProvider
3 大类;
2. 实现 factory
函数并 default 导出。
所以很明显了,下一步就是研究一下 adapter
和 factory
了。
Adapter & Factory
我们先来看一下渲染模块的架构图:
更多内容见 渲染模块设计。结合架构图和 React Renderer 的代码,我们基本已经捋清了:
- setRuntime 需要注入的,是一些框架相关的最底层的基础类或函数,也就是框架的基础能力,比如 React 的 createElement、Component、PureComponent 等。其本质是框架暴露出的底层 API;
- setRenderer 需要注入的,是用 runtime 基础能力实现的 lowcode-engine 的基础概念,如 PageRenderer、ComponentRenderer、BlockRenderer 等。其本质其实就是各种组件 Class,只不过是比较基础的组件;
- setConfigProvider 就是一个载入全局配置的 Provider,一般是 UI 组件库提供的能力;
- factory 比较复杂,算是一个高阶函数,返回值是一个可以 jsx 的 class。React Renderer 的源码我们可以看出,这个 class 继承了 renderFactory() 返回的类,也继承了 class Component,然后复写了一些方法。其它都好理解,关键是这个 renderFactory 做了什么。简单说,就是利用刚才 adapter 注入的 API 实现渲染逻辑。再具体点,就是加载刚才注入 adapter
中的各种 API,然后按照当前框架的语法,实现 lowcode-engine 各种概念的渲染逻辑,当然还有对 schema 递归处理的能力。
拨开迷雾看本质,实际上适配层最重要的就是这个 renderFactory
内部逻辑的实现,其他仅仅是为其提供基础 API 而已,可以看成是一些封装好的基础 utils。而 renderFactory 当中最主要的逻辑就是加载 schema 和 components 然后渲染。那么怎么实现 Vue Renderer 呢?
Vue Renderer
很遗憾,目前的结果没那么理想。adapter
的代码是按照 React 的习惯和逻辑实现的,笔者可以找到 React.createElement
与 Vue.h
是非常相似的,但是其他 API 相差实在是有点大。比如 context 的使用,React 中 createContext/Provider
和 Vue 中的 provide/inject
用法还是有很大差异的。所以实际上只有类 React 框架,比如 Rax 是可以比较方便的接入现有 adapter 层的。要想实现 Vue Renderer,理论上需要把 Vue 的底层 API 加工成 React 的 API,倒不是不可能,但是成本实在太大了,而且也不排除有些 API 根本无法转换的可能。与其如此,笔者可能会选择自己实现一个 renderFactory 函数,把解析 schema 和 components 的逻辑,用 Vue 的语法再实现一遍,也就是基本无法复用 @alilc/lowcode-renderer-core
提供的能力了。
而且!而且!而且!这里还有一个更加重要的问题,那就是现有的可视化编辑部分是用 React 实现的,这意味着即使实现了 Vue Renderer,你的组件也不能在编辑器的画布中展示出来,官方也说了短期内不会支持 Vue 画布。但是 schema + components => 渲染/出码 这样的功能还是可以跑通的。
结论
所以最后的结论是:目前要实现 Vue Render 成本非常大。尤其解决可视化编辑器画布渲染这块,有相当大的工作量。
那么这条路是不是就该放弃了呢?
至少对于笔者来说不是。《lowcode-engine 协议浅析》中也说了,笔者的目的是为了提高开发效率,目标用户是研发,可视化编辑并不是必须的功能。所以只要 schema + components => 渲染/出码 这段功能可以较低成本实现就行。
另外,协议也就是 schema 的确是框架无关的,这个协议是可以 100% 复用的,这就已经是很大的一笔收获了。最不济,还可以通过现有可视化编辑器输出的 schema,来判断其组件是如何设计和封装的,其中最值得参考的就是表单和列表组件,这绝对是一次绝好的偷师机会。
所以接下来笔者计划就是用 schema + Vue 成功封装出一个表单组件和列表组件,相信做完这个,离真正的 Vue Render 也就不远了。
- 看我用 Linux 带娃,培养编程兴趣
- 【微前端】Qiankun Vue3 配置
- 通用 Form API 协议 - 基础版
- Final Form 设计思路浅析
- 【低代码漫谈】 lowcode-engine - Vue Renderer 尝试
- Redash 设计理念浅析
- Metabase 设计理念浅析
- DataEase 设计理念浅析
- 开源 BI 工具调研:Superset、Metabase、Redash、DataEase(一)- 基本数据
- Ubuntu 一行命令装软件——VirtualBox
- 程序员怎么给娃起名?当然是写个脚本!
- GoGoCode - 像用 Jquery 一样方便地处理 AST
- 【gRPC】Web 请求的 TS 封装 - 完美版
- 【gRPC】2 分钟学会 Protocol Buffer 语法
- 【gRPC】封装前端网络请求的核心思想 - TS版
- 如何避免 Vue 的漏洞破坏单向数据流
- 用函数式编程写出“傻瓜”都能看懂的代码
- Vue3 最佳实践之编码规范