Skip to content

Commit

Permalink
docs: update
Browse files Browse the repository at this point in the history
  • Loading branch information
wwsun committed Jan 25, 2024
1 parent d0f1b8f commit 30b4876
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 5 deletions.
113 changes: 110 additions & 3 deletions apps/website/docs/designer/design/overview.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,112 @@
# 技术架构概览

:::tip
正在编写中,敬请期待。
:::
我们在 2023年8月底[正式开源了 Tango 低代码引擎](https://juejin.cn/post/7273051203562749971)。Tango 是一个基于源码的低代码设计器框架,支持直接基于项目源码提供低代码可视化开发能力,可以无缝的与既有的本地开发工作流进行集成,从而提供渐进式的低代码开发能力。

![Tango 低代码引擎使用演示](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30108735057/7ba9/dced/9ac3/420f6e04b371dd47de06e7d71142560d.gif)

按照计划,我们在 2023年9月底[发布了 1.0 alpha 版本](https://github.com/NetEase/tango/releases),在此版本中我们遵循 **“最小内核”** 的原则对 Tango 的核心实现进行了大幅的重构,剥离了大量冗余的代码实现。

为了帮助大家更近一步的了解 Tango 开源版本的核心构成与代码实现,本文将会详细揭秘 Tango 低代码引擎的设计思考与实现过程。

- Github 仓库:<https://github.com/NetEase/tango>
- 发行历史:<https://github.com/NetEase/tango/releases>
- 文档站点:<https://netease.github.io/tango/>

## 低代码可视化搭建之殇

从实现上看,低代码搭建能力的核心是 UI 可视化编程。借助 UI 可视化编程,可以大大的弱化使用者对于代码编程的感知,但在真实的业务需求场景中,我们面临着大量的复杂的应用逻辑,使用者很难借助 UI 操作表达功能逻辑。例如下图中的合同管理,资金结算等页面。如果借助于传统的低代码方案,通常会发现,很容易一条路走到黑,没有回头路。所以,经常会有开发者抱怨,稍微复杂的场景下,低代码的效率甚至不如写代码。

![在实际业务场景中面临大量难以低代码开发的前端应用](https://p5.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30577891541/dac5/e050/986b/9466633e32518be2685e882618343251.png)

## 传统低代码方案的问题

我们不妨先简单分析一下传统的低代码方案的问题。传统的低代码搭建方案往往采用定义私有 Schema 协议来可视化表达视图逻辑,也就是将代码逻辑转换为私有的描述,大致的原理可以参考下面这张图。

![基于 Schema 的低代码可视化搭建方案](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30577932595/1456/2196/aeee/a10fbe99c3f6d050629b140ecfbbc257.png)

这类方案很容易面临不断膨胀的私有 JSON 协议。并且,私有协议扩展性和灵活性差,难以达到图灵完备状态。例如在我们的实际开发过程中,传统的低代码方案会面临各种各样的扩展性卡点。此外,开发能力往往受限于内置的组件和模板。且难以复用现有的前端资产,例如组件和代码等等。对于开发者而言,私有协议也导致问题定位难,调试难。

借助于私有协议的搭建方案通常适合于轻业务逻辑的简单类表单,营销类的活动页面等等,很难用于复杂的业务逻辑搭建场景,因为私有协议难以有效的应对这类场景的复杂性和灵活性需求。虽然,有些方案提供了协议转代码的能力,但通常只实现了单向转码,可视化开发和代码开发是两条完全割裂的路径。

**在此基础上,我们就需要重新思考低代码搭建协议的设计问题。**

## 从私有搭建协议到公有协议

那么,我们能否不使用私有协议,而是采用公有协议?

答案是,可以的![ESTree](https://github.com/estree/estree) 规范作为主流的处理 JavaScript 源代码的标准社区协议,被广泛用于浏览器 JavaScript Parser 的实现。借助于 ESTree 协议,可以完美的实现对源码逻辑的描述,并且社区有大量的工具可以帮助我们完成这个过程。

![基于ESTree规范,实现双向互转的低代码搭建能力](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30578051842/b7b4/f625/9458/3ead74325547a45f501ae99c7270cffa.png)

因此,我们尝试使用 ESTree 规范来实现低代码搭建过程。借助于 ESTree 规范,我们无需定义私有的渲染描述协议,并且可以低成本的实现代码到协议,协议到代码到互转。借助于双向转码的能力,我们获得全新的低代码开发体验。

## Tango 低代码引擎实现原理

基于这个思路,我们设计了基于 ESTree 规范的低代码引擎方案 -- Tango。可以通过下面这张图来简单的描述下实现逻辑:

![Tango 低代码引擎实现分析](https://p5.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30578073085/61cd/b2db/e103/9ed9dd334a6679c6ec18a02270efe446.png)

首先将源代码解析为 AST。用户的拖拉拽等操作则映射为对 AST 的遍历和修改。最后将新的 AST 重新生成代码,交给设计器沙箱去渲染执行。而对 AST 的解析、遍历、修改、生成,则可以借助大量的社区工具,这里我们选择的是 babel!

> AST 的全称是抽象语法树,是一种分层的程序表达,根据编程语言的语法呈现源代码的结构。

![大量的工具基于 AST 实现](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30578121562/578f/1bac/9dd3/69b5b4e5c1171babf4db427f41981b4d.png)

其实,数量众多的前端工具库都是基于 AST 操纵实现的。我们可以发现,在任意的前端项目中的 package.json 里的 devDependencies 里的很多工具包是基于 AST 解析操纵实现的,例如 JS 的转译,代码压缩,ESLint 等等,我们可以阅读这些工具的源码来进一步的学习。

![将源码转为 AST 描述的基本过程](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30578132788/1f4b/d7d7/56b8/feb4220a611afae0629d76758479118a.png)

如图所示,将源代码转为 AST 描述的基本过程包括词法分析和句法分析两个阶段:

- 词法分析:借助词法分析器将代码字符串分割为标记列表。
- 句法分析:借助句法分析器将标记数据转为 AST 描述。

最后,我们可以获得源代码的结构化描述树。有很多工具可以帮我们来实现这个过程,例如 babel -- 它可以帮助我们轻松的实现代码到 ast,ast 遍历修改,ast 到代码的过程。

## 基于 AST 实现搭建的基本过程

我们来看一下使用 ast 实现搭建逻辑的基本过程。

看一个具体的例子:通过修改 AST,在 Page 中插入一个 Section 节点。

![基于 AST 实现搭建逻辑](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30579119959/aea0/6e5a/6aba/979804c4270f5ad05b84da2220624afd.png)

中间这段代码,展示了核心的逻辑,通过遍历整个 AST 中的所有 JSXElement 节点,找到第一个 Page 元素,然后在 Page 元素的 children 里插入新的 Section 节点。这只是一段演示代码,具体的过程比这个要复杂的多,因为有很多的边际逻辑要处理。最后,我们可以将 ast 重新生成为代码,得到我们想要的结果。

## Tango 的数据变更流程设计

了解了基本的实现原理后,我们来看一下低代码引擎的数据变更流程设计。

![数据变更流程设计](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30579135078/e381/579c/61ed/91e110abd1d17c742e8aa7d407d0327b.png)

首先是引擎初始化。源码文件会被引擎内核解析进行状态初始化。接下来,对于用户的操作,会触发浏览器事件,引擎接收到相应的事件,触发内核中的状态变更,更新 AST。

然后,内核会基于新的 AST 的同步生成代码,由引擎将代码同步给渲染沙箱。渲染沙箱感知到代码变化后,会触发页面重新渲染,也就是沙箱的 HMR 过程。

## 基于源码的在线渲染沙箱设计

接下来,我们需要考虑的是如何在浏览器中执行 JavaScript 源码工程?有很多方案可以选择,我们选择的方案是 [sandpack](https://sandpack.codesandbox.io/),它是由 CodeSandbox 开源的可以在浏览器中实时运行 JavaScript 项目的的工具库。在具体实现上,[我们对 sandpack 进行了一系列的改造](https://juejin.cn/post/7102243774985666596),以满足低代码生产环境的需要。

基于 sandpack 的在线渲染沙箱方案如下图图所示。

![Tango 沙箱设计](https://p5.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30579143007/ab5d/3611/950e/5ae276b6131a4a479d6fb10e50ebbfcb.png)

在实现上,主要包括 3 个部分,分别是:​

- 低代码沙箱:它是一个开箱即用的前端组件,只需要传入源代码和构建配置信息即可完成前端项目的构建和执行。
- 在线 Bundler:是低代码沙箱的核心,用来在浏览器上构建和执行源代码,本质上是一个在浏览器端运行的简化版 webpack。
- 打包服务:是一个 node 服务,用来对 npm 包执行预构建和资源合并。

从沙箱执行流程来看,首先 Sandbox 组件将项目的源代码和 compile 指令使用 postMessage 传递给在线 Bundler,在线 Bundler 在接收到 compile 指令后,bundler 会从 packager 打包服务加载项目的 npm 依赖,然后编译和执行代码,最后发送 success 消息给低代码沙箱。

## Tango 低代码引擎的构成

结合上面的介绍,在构成上,Tango 低代码引擎主要包括 3 个核心组成部分,分别是:

- 引擎内核:扶额建立文件,节点模型,提供输入输出能力。
- 拖拽引擎和可视化面板:提供可视化开发能力
- 渲染沙箱:提供源码在浏览器上的编译执行能力。

![引擎构成](https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/30579167082/1404/27e2/b8e5/0c719ca82494a282080d73adeff7196e.png)

借助于 Tango 低代码引擎,我们可以为开发者提供全新的在线开发体验,支持源码级的自定义能力。对可视化开发而言,可视化配置会触发 AST 的修改,进而会重新生成对应的源码。而对源码开发而言,修改源码后会同步更新 AST。
4 changes: 2 additions & 2 deletions apps/website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ const config = {
title: '社区',
items: [
{
label: 'Stack Overflow',
href: 'https://stackoverflow.com/questions/tagged/netease-tango',
label: 'Discussions',
href: 'https://github.com/NetEase/tango/discussions',
},
{
label: 'Discord',
Expand Down

0 comments on commit 30b4876

Please sign in to comment.