第 97 期 - Tango 低代码引擎沙箱能力剖析
摘要
本文主要讲述 Tango 低代码引擎的沙箱能力,阐述其采用 CodeSandbox 沙箱能力的原因、沙箱基本结构与工作流程、相关优化改造、如何接入 Tango 沙箱,还提及 Tango 的开源进展。
Tango 基本介绍
Tango 是用于构建低代码平台的框架,以源代码为中心,可执行和渲染前端视图,提供低代码可视化搭建能力,用户操作会转换为对源代码的修改,构建的工具或平台能实现源码进、源码出,与企业研发体系集成。
开源进展
Tango 设计器引擎已开源,可通过开源代码库(https://github.com/NetEase/tango)、文档地址(https://netease.github.io/tango-site/)、社区讨论组(https://github.com/NetEase/tango/discussions)了解进展。文档已更新,欢迎加入社区,有问题可通过 Github Issues 反馈。
为什么 Tango 需要沙箱
- 与传统方案对比:传统基于 DSL 的低代码方案需实现 DSL 语法与渲染器,Tango 是基于 AST 驱动的面向源码的低代码方案,写法更灵活,但面临支持源代码实时运行的挑战,且要考虑三方依赖加载与运行,所以需要独立沙箱。
- 调研其他方案:调研过 Sea.js 这类 AMD 加载方案,依赖固定,需预构建产物,不能灵活添加依赖;SystemJS 和 ViteSandbox 这类 ESM 方案,产物以 CommonJS 为主,缺少 ESM 产物,且 Tango 后续优化减少沙箱初始化时间,所以未采用。
- 采用 CodeSandbox 的原因:基于 CodeSandbox 的沙箱能力实现,优势在于提供完整、接近本地开发的运行时环境,支持直接拉取
npm包并运行,借助Babel转译新语法,模拟 CommonJS 运行环境,在浏览器直接运行源码,沙箱运行在iframe内可隔离环境,避免污染全局变量。
Tango 沙箱的基本结构
- 沙箱前端组件:开箱即用,传入代码和配置即可渲染应用。
// 示例代码可能类似这样简单调用组件并传入参数
const sandboxComponent = new SandboxComponent({code: 'yourCode', config: 'yourConfig'});
sandboxComponent.render();
- 在线打包器:提供浏览器端构建能力,类似浏览器版本的
webpack,最终是独立iframe。 - 沙箱后端服务:预构建依赖资源,提供资源合并等服务,加速沙箱内部构建打包。
Tango 沙箱的工作流程
代码准备
平台引用沙箱组件,通过postMessage传递代码给沙箱。
依赖初始化
- 轻量初始化:CodeSandbox 内部实现转译逻辑,初始化依赖时较轻松,只需获取
dependencies里必要依赖,忽略devDependencies和@types开头的本地开发才用的依赖。 - 获取依赖的方案
- 默认远程在线打包方案:通过
dependency - packager服务在线拉取依赖,解析URL中的包名和版本号,在服务端执行yarn install安装npm包,解析依赖关系,返回被依赖文件。 - 兜底方案:从
unpkg/jsdelivr等npm包资源的CDN获取依赖,当项目引入被排除资源时,沙箱前端请求此作为兜底,不过若缺失文件多,网络请求开销大,所以使用Service Worker做资源缓存。
- 默认远程在线打包方案:通过
转译代码
- 转译流程开始:调用
compile()方法转译,传入沙箱的参数除代码外,还有template参数指定转译Preset,Preset类似webpack配置文件。 - Manager 实例:
Preset初始化后,初始化Manager实例控制转译流程生命周期,按照前面方式初始化项目依赖,依赖变更时重新初始化Manager实例。 - 模块转译:传入沙箱的代码传入
Manager,实例化为TranspiledModule,解析模块依赖关系,从入口模块开始,根据Preset规则对每个模块递归调用Transpiler转译,复杂Transpiler如BabelTranspiler会用Web Worker队列提升效率。
执行代码
- 运行时环境模拟:沙箱运行时模拟
CommonJS环境,如require、module、exports、global等方法和变量。 - 执行核心代码:核心代码将所有全局变量和方法整理,封装代码为立即执行函数,调用
eval()执行并传入CommonJS的方法和变量,若代码引用其他文件,require()方法递归执行并返回产物。
沙箱的优化改造
Tango 上的应用是完整项目,对沙箱构建性能和加载速度要求高,具体优化细节可参考《云音乐低代码:基于 CodeSandbox 的沙箱性能优化》,修改后的代码在 GitHub 上可找到。
接入 Tango 沙箱
- 跨域兼容:沙箱在独立
iframe且域名独立,与设计器跨域,将设计器平台与沙箱的document.domain设为相同父域名,并添加Origin - Agent - Cluster:?0的HTTP响应头实现跨域通信。 - 封装 React 组件:封装
@music163/tango - sandbox供设计器使用,分为IFrameProtocol、PreviewManager、Sandbox三个部分。- IFrameProtocol:负责与沙箱通信,监听
message事件接收沙箱消息获取生命周期,在iframe内部调用postMessage()向沙箱传递事件控制沙箱。 - PreviewManager:管理沙箱基本渲染,借助
IFrameProtocol与沙箱通信,代码变化时向沙箱发送compile消息触发构建和渲染。 - Sandbox:渲染沙箱的
React组件,除挂载iframe外,还有沙箱配置、注册事件监听函数、消息传递、路由管理等功能,props变化时更新沙箱代码和iframe路由等。
- IFrameProtocol:负责与沙箱通信,监听
总结
简单介绍 Tango 低代码引擎沙箱能力,分析 CodeSandbox 基本结构和工作流程,通过 CodeSandbox,Tango 实现可视化预览与搭建能力,提供便捷开发体验。Tango 已完成部分开源并发布RC版本,今年将持续推进开源并优化文档,未来还会开源更多内部实践。
