Dumbbell
低代码二次开发工具,将阿里低代码引擎的 schema,转换为 react 函数组件并且可进行二次开发的源码,源码将脱离低代码引擎成为 ”干净的“ react 项目。
项目代码是基于 rush+pnpm 的多包项目,请参考:
存在的意义
低代码引擎导出的源码存在如下问题:
- 导出的源码,绝大部分代码对于二次开发来说都是都是黑盒
- 导出的源码时基于 class 的 react 组件且 react 版本是 16.x
- 导出的源码项目,使用 yarn 或者 pnpm 初始化会报错,只能使用 npm
- 要运行导出的源码项目,就必须依赖低代码引擎相关的依赖,并不是真正意义上的“源码项目”
使用方法
目前处于开发阶段功能还不稳定,此期间会频发布
$ npx stsc
配置文件
import { resolve } from 'node:path';
import { defineConfig } from '../packages/stsc/src';
export default defineConfig({
schemaFile: './lc-config/schema.json',
assetsFile: './lc-config/assets.json',
entryHtmlFile: './index.html',
});
- 从 scheam
[
{
"componentName": "Page",
"props": {
"ref": "outerView",
"style": {
"height": "100%"
}
},
"state": {
"text": {
"type": "JSExpression",
"value": "\"outer\""
},
"isShowDialog": {
"type": "JSExpression",
"value": "false"
}
},
"lifeCycles": {
"componentDidMount": {
"type": "JSFunction",
"value": "function componentDidMount() {\n console.log('did mount');const {} = state;\n}"
},
"componentWillUnmount": {
"type": "JSFunction",
"value": "function componentWillUnmount() {\n console.log('will unmount');\n}"
}
},
"methods": {
"onClick": {
"type": "JSFunction",
"value": "function onClick() {\n this.setState({\n isShowDialog: true\n });\n}"
},
"closeDialog": {
"type": "JSFunction",
"value": "function closeDialog() {\n this.setState({\n isShowDialog: false\n });\n}"
}
},
"children": [
{
"componentName": "Button",
"props": {
"type": "primary",
"children": "主按钮",
"htmlType": "button",
"size": "middle",
"shape": "default",
"block": false,
"danger": false,
"ghost": false,
"disabled": false,
"onClick": {
"type": "JSExpression",
"value": "onClick"
}
}
},
{
"componentName": "Modal",
"props": {
"visible": {
"type": "JSExpression",
"value": "isShowDialog"
},
"onCancle": {
"type": "JSExpression",
"value": "closeDialog"
}
}
},
{
"componentName": "Progress",
"props": {
"percent": 20,
"status": "active",
"type": "line",
"showInfo": false,
"steps": 0,
"strokeLinecap": "round",
"strokeWidth": 0
}
}
]
}
]
- 到源码
component.tsx
import React, { useEffect, forwardRef, useImperativeHandle } from 'react';
import { Button, Progress, Modal } from 'antd';
import { useInternalReducer } from './use-internal-reducer';
export const Page = forwardRef((props: any, ref) => {
const { style } = props;
const [state, setState] = useInternalReducer();
const { text, isShowDialog } = state;
function onClick() {
setState({
isShowDialog: true,
});
}
function closeDialog() {
setState({
isShowDialog: false,
});
}
useEffect(() => {
const componentDidMount = () => {
console.log('did mount');
const {} = state;
};
componentDidMount();
return () => {};
}, []);
useEffect(() => {
const componentWillUnmount = () => {
console.log('will unmount');
};
return () => {
componentWillUnmount();
};
}, []);
useImperativeHandle(ref, () => {});
return (
<div style={style}>
<Button
type="primary"
children="主按钮"
htmlType="button"
size="middle"
shape="default"
block={false}
danger={false}
ghost={false}
disabled={false}
onClick={onClick}
/>
<Modal visible={isShowDialog} onCancel={closeDialog} />
<Progress percent={20} status="active" type="line" showInfo={false} steps={0} strokeLinecap="round" strokeWidth={0} />
</div>
);
});
export default Page;
use-internal-state.ts
import { useReducer } from 'react';
const initialState = { text: 'outer', isShowDialog: false };
const reducer = (state, action) => {
const { type, ...resetState } = action;
switch (type) {
case 'update':
return { ...state, ...resetState };
default:
throw '未定义此类型的操作';
}
};
export const useInternalReducer = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return [state, (newState) => dispatch({ type: 'update', ...newState })];
};
index.tsx
import React, { useRef } from 'react';
import Page from './component';
export default (props) => {
const ref = useRef();
return <Page ref={ref} style={{ height: '100%' }} {...props} />;
};
测试
使用Vitest作为测试框架,可以查看测试用例了解功能:
$ cd packages/stsc
$ rushx test
示例
示例代码目录 example,可以在此项目进行调试。
待办列表
-
加载
stsc
的配置文件- √ 嗅探
stsc.config.ts
- √ 加载
schema.json
- √ 注册
assets.json
- √ 解析远端
assets.packages
并可配置是否自动下载依赖 - √ 解析本地
assets.packages
- √ 解析远端
- √ 嗅探
-
√ 将
schema.state
解析为useReducer
-
√ 将
schema.methods
解析为函数组件中的方法 -
√ 解析
schema.children
-
√ 转换
componentDidMount
-
√ 解析
schema.props
- √ 根节点
props
,处理ref
- √ 非根节点
props
- √ 解析
JSONValue
类型属性 - √ 解析
JSSlot
类型属性 - √ 解析
JSExpression
类型属性 - √ 解析
JSFunction
类型属性 - 递归解析以上属性类型(嵌套)
- √ 根节点
-
将
schema.lifeCycles
解析为useEffect
- √ 转换
componentWillUnmount
- √ 转换
componentWillMount
- 转换
shouldComponentUpdate
- 转换
componentDidUpdate
- √ 转换
-
解析
schema.dataSource
- √ 并行请求(async)、串行请求(sync)
- 是否是初始化是请求数据
- fetch 初始超时
- 所有请求完成之后调用钩子
- 请求失败调用 error 钩子
-
解析
schema.css
-
基于
schema.chunk
拆分component
代码 -
完善脚手架项目管理流程
-
完善代码 lint 及格式化