低代码沙箱接入
沙箱是搭建产物(对于 Tango 主要是源码)的运行环境,它是一个独立的环境,可以在其中运行搭建产物,以便于开发者可以在不影响生产环境的情况下进行调试和测试。
Tango 沙箱由三个部分构成,包括低代码沙箱前端组件、在线打包器、沙箱后端服务,如下图所示。
- 沙箱前端组件:一个开箱即用的沙箱组件,只需要传入代码和配置就可以完成应用的渲染。
- 在线打包器:提供搭建产物的浏览器端构建能力,类似于一个浏览器版本的 webpack,此部分逻辑主要来自于 sandpack 项目。
- 沙箱后端服务:对依赖的资源进行预构建,以及提供资源合并等服务,用来加速沙箱内部的构建打包过程。
在接入前,请确认本地或服务器上已经安装了 Node.js 与 npm/yarn,且 Node.js 的版本大于等于 16。若本地没有安装 Node.js 或版本不满足需求,可以使用 nvm 来安装并实现多版本管理。
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 16
nvm use 16
npm install --global yarn
沙箱的前端组件接入
Tango 封装了一份标准的沙箱实现 @music163/tango-sandbox
,在与 Tango 设计器一同使用时,你只需要传入 bundlerURL
指定沙箱地址即可。
点击展开代码
<Designer engine={engine} sandboxQuery={sandboxQuery}>
<DesignerPanel>
<Sidebar></Sidebar>
<WorkspacePanel>
<WorkspaceView mode="design">
<Sandbox
// 将 bundlerURL 替换为已部署的沙箱的地址
bundlerURL="https://sandbox.example.com"
// 从沙箱的全局变量中获取挂载的 UMD 组件库的 menuData 与 prototypes 信息
// 如果上述信息可以通过其他方式获取到,你也可以直接调用相关方法注册
onMessage={(e) => {
if (e.type === 'done') {
const sandboxWindow: any = sandboxQuery.window;
if (sandboxWindow.TangoAntd) {
if (sandboxWindow.TangoAntd.menuData) {
setMenuData(sandboxWindow.TangoAntd.menuData);
}
if (sandboxWindow.TangoAntd.prototypes) {
workspace.setComponentPrototypes(sandboxWindow.TangoAntd.prototypes);
}
}
if (sandboxWindow.localTangoComponentPrototypes) {
workspace.setComponentPrototypes(sandboxWindow.localTangoComponentPrototypes);
}
setMenuLoading(false);
}
}}
/>
</WorkspaceView>
<WorkspaceView mode="code">
<CodeEditor />
</WorkspaceView>
</WorkspacePanel>
<SettingPanel />
</DesignerPanel>
</Designer>
CodeSandboxProps
如果你需要直接使用沙箱组件,可以参考如下常用的 props 定义,这些 props 主要暴露了 CodeSandbox 内部的一些参数,以及封装了 Tango 所需的事件回调方法。不过这些参数仅是简单透出而已,不代表这些参数能兼容 Tango 的设计器,例如在 Tango 的设计器里 template
应该始终为 create-react-app
,因为 Tango 目前仅支持 React 的 JavaScript 应用搭建。
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
bundlerURL | 沙箱地址 | string | - |
iframeId | iframe 唯一标识符,当有多个实例的时候必须要传 | string | sandbox-container |
template | 模板类型 | angular-cli | create-react-app | create-react-app-typescript | svelte | parcel | vue-cli | static | solid | create-react-app |
moduleType | 模块类型 | esm | cjs | - |
files | 文件列表 | { [path: string]: { code: string } } | - |
entry | 入口文件 | string | /index.js |
dependencies | 依赖信息 | { [depName: string]: string } | - |
externalResources | 单独注入的 JS 与 CSS 资源 | string[] | - |
startRoute | 起始路由 | string | / |
routerMode | 路由类型 | history | hash | history |
eventHandlers | 事件监听 | { [path: string]: (e: Event) => void } | - |
onFileChange | 文件发生变更时触发事件 | (files: { [path: string]: { code: string } }, sandpack: ISandpackContext) => void | - |
onMessage | 沙箱消息监听事件 | (frame: HTMLIFrameElement) => void | - |
style | 沙箱样式 | React.CSSProperties | - |
在线打包器
Tango 预置的沙箱方案是基于 CodeSandbox 实现的,并在之上做了适配 Tango 的修改,你可以在 这里 查看我们修改后的实现。由于沙箱的能力并不属于 Tango 的核心部分,因此你需要单独部署 CodeSandbox 的沙箱服务。
准备沙箱产物
使用预构建的资源
我们的代码仓库配置了 GitHub Actions,它会在代码变更时自动构建沙箱,然后将最终的产物上传至 GitHub Releases。
你可以直接在 这里 下载最新版本的产物,下载后将其解压至 ./www
目录下即可。
手动构建
如你需要对沙箱做一些修改(例如私有化部署了相关服务,需要修改请求地址),你可以通过 clone 代码仓库到本地,然后执行指令构建产物。
-
克隆代码仓库到本地:
# 由于代码仓库较大,为节省时间,此处指定了 --depth 1
git clone https://github.com/NetEase/codesandbox-client.git --depth 1 -
安装依赖:
cd codesandbox-client
yarn -
修改代码并测试。
-
构建产物:
yarn build:deps
yarn build:sandpack -
构建完成后,你可以在
./www
下找到最终构建的产物。
部署沙箱
CodeSandbox 的沙箱服务需要确保部署环境支持 HTTPS 访问。你需要一个可自主控制的域名,并 为其获取有效的 SSL 证书。你可以使用 Let's Encrypt 或 ZeroSSL 等方法获取证书,或者使用主机服务提供商提供的 HTTPS 方案。
对于本地开发等无法准备有效 SSL 证书的情况,你可以将域名在 hosts 文件里指向 127.0.0.1
,然后使用 Caddy 提供的自签发证书功能(该配置已预置在仓库的 Caddyfile
中),或者使用下面的命令手动生成证书并添加信任,然后将其写入配置文件:
# 为 example.com 及其子域名生成一个有效期 10 年的自签发证书
# 自签证书默认不会被浏览器信任,只能用于本地开发,线上部署请使用合法的 SSL 证书
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
-subj "/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:*.example.com" \
-keyout example.com.key -out example.com.crt
使用 Caddy 部署
我们在项目内部提供了一个 Caddy 配置文件,你可以在这个配置文件中调整参数,然后使用 Caddy 启动服务器。
-
从 Caddy 的下载页面 下载可执行文件,或参考 Caddy 的文档 了解其他安装方式。
-
确保构建产物位于
./www
目录下,且当前目录下存在Caddyfile
文件。如果你是直接从 Releases 页面下载的沙箱产物,可以从 这里 下载最新的Caddyfile
文件。 -
将沙箱运行的域名的 DNS 记录解析到你的服务器的 IP 地址;如果你是在本地开发,你可以在 hosts 文件里将测试的域名指向
127.0.0.1
。 -
如果你需要使用 Caddy 的自动 HTTPS 功能(包括本地开发),请将
Caddyfile
里的:8080
替换为你自己的域名,Caddy 会为该域名自动签发 SSL 证书;如果你在服务上游有其他代理服务器负责处理 HTTPS,则可以不做修改,但请确认上游服务器代理的端口与Caddyfile
里的端口保持一致。 -
在 4 开启了 HTTPS 功能的基础上,如果你需 要 Caddy 自动签发合法的 HTTPS 证书 (而不是本地开发用的自签证书),请将
Caddyfile
里的local_certs
一行删除;如果需要手动指定证书,请参考 Caddy 文档。 -
Caddy 的配置文件里默认监听的 HTTP 端口是
8080
端口,HTTPS 则是8443
端口,如果需要修改为默认的80
与443
端口,请修改Caddyfile
里的http_port
与https_port
。 -
如果一切准备就绪,你可以使用下面的指令启动 Caddy:
caddy run
-
部署完成后,在浏览器上访问你配置的域名端口,例如若你在 4 里将域名改为
local.example.com
,则访问https://local.example.com:8443
即可。若浏览器的标题栏显示为 Sandbox - CodeSandbox 则表示部署成功。
使用 Docker 部署
我们在项目内部提供了一个 Dockerfile
,它会自动从源码构建产物,并自动使用 Caddy 的 Docker 镜像部署。你可以在部署前按照上面的步骤按需修改 Caddyfile
文件,然后使用下面的指令构建镜像并启动容器:
docker build -t tango-codesandbox .
docker run -p 8443:8443 tango-codesandbox
使用 nginx 部署
如果你更熟悉 nginx,可以参考 这里 的配置修改,然后将 SSL 证书更新至配置中,或是通过 Certbot 或 acme.sh 等工具签发证书并自动修改 nginx 配置。
常见问题
-
沙箱部署后显示白屏,并在控制台提示
Error: Can't detect sandbox ID from the current URL
这是正常情况,沙箱需要引擎传入代码后才能正常执行,只需确认浏览器的标题栏显示为 Sandbox - CodeSandbox 即可。
-
沙箱部署必须要启用 HTTPS 吗?
是的,因为 CodeSandbox 会注册 Service Worker 来处理请求缓存。此外由于 Chrome 的 安全策略 限制,若需要与不同域名的 iframe 通过修改
document.domain
通信,必须在 top 与 iframe 的 HTTP 响应头中添加Origin-Agent-Cluster: ?0
响应头,而且该响应头仅在 HTTPS 下生效。 -
本地开发没有合法的 SSL 证书该怎么办?
你可以在操作系统的 hosts 文件里将任意域名指向
127.0.0.1
,并为该域名签发自签证书。Caddy 会在配置文件中指定了访问域名的情况下自动签发证书,并自动将 CA 证书加入当前设备的可信根证书,因此你不需要再做其他操作。不过如果你使用了其他的部署方案,或者有自己的理由自行签发证书,可以使用下面的指令创建证书:# 为 example.com 及其子域名生成一个有效期 10 年的自签发证书
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
-subj "/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:*.example.com" \
-keyout example.com.key -out example.com.crt需要注意的是,在线上使用时,你必须提供一个可以被浏览器信任的合法的 SSL 证书。
-
我无法在 Tango 设计器里选中或拖拽沙箱里的组件
这是因为 Tango 设计器的沙箱是通过 iframe 嵌入的,而 iframe 的安全策略是不允许跨域访问的,所以 Tango 与沙箱会通过修改
document.domain
为同级域名的方式来实现跨域访问。