feat: ReactProvider

This commit is contained in:
wuyue.xht 2020-05-18 16:03:00 +08:00
parent 75a2020a6e
commit 0e50a2056a
8 changed files with 214 additions and 0 deletions

View File

@ -0,0 +1,4 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

View File

@ -0,0 +1 @@
# 低代码引擎运行时框架

View File

@ -0,0 +1,5 @@
{
"plugins": [
"build-plugin-component"
]
}

View File

@ -0,0 +1,43 @@
{
"name": "@ali/lowcode-react-provider",
"version": "0.8.14",
"description": "React Provider for Runtime",
"files": [
"es",
"lib"
],
"main": "lib/index.js",
"module": "es/index.js",
"scripts": {
"build": "build-scripts build --skip-demo",
"test": "ava",
"test:snapshot": "ava --update-snapshots"
},
"ava": {
"compileEnhancements": false,
"snapshotDir": "test/fixtures/__snapshots__",
"extensions": [
"ts"
],
"require": [
"ts-node/register"
]
},
"license": "MIT",
"dependencies": {
"@ali/lowcode-runtime": "^0.8.13",
"react": "^16",
"react-dom": "^16",
"@recore/router": "^1.0.11"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
"build-plugin-component": "^0.2.16",
"@types/node": "^13.7.1",
"@types/react": "^16",
"@types/react-dom": "^16"
},
"publishConfig": {
"registry": "https://registry.npm.alibaba-inc.com"
}
}

View File

@ -0,0 +1,5 @@
import ReactProvider from './provider';
import { Router } from '@recore/router';
export { Router };
export default ReactProvider;

View File

@ -0,0 +1,43 @@
import { Component, createElement } from 'react';
import { app } from '@ali/lowcode-runtime';
interface IProps {
getPageData: () => any;
[key: string]: any;
}
interface IState {
schema: object | null;
}
export default class LazyComponent extends Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
schema: null,
};
}
async componentDidMount() {
const { getPageData } = this.props;
if (getPageData && !this.state.schema) {
const schema = await getPageData();
this.setState({ schema });
}
}
render() {
const { getPageData, ...restProps } = this.props;
const { schema } = this.state;
const Renderer = app.getRenderer();
const Loading = app.getLoading();
if (!Renderer || !schema) {
if (!Loading) {
return null;
}
// loading扩展点
return createElement(Loading);
}
return createElement(Renderer as any, { schema, loading: Loading ? createElement(Loading) : null, ...restProps });
}
}

View File

@ -0,0 +1,104 @@
import { createElement, ReactType, ReactElement } from 'react';
import ReactDOM from 'react-dom';
import { Router } from '@recore/router';
import { app, Provider } from '@ali/lowcode-runtime';
import LazyComponent from './lazy-component';
export default class ReactProvider extends Provider {
// 定制构造根组件的逻辑,如切换路由机制
createApp() {
const RouterView = this.getRouterView();
let App;
const layoutConfig = this.getLayoutConfig();
if (!layoutConfig || !layoutConfig.componentName) {
App = (props: any) => (RouterView ? createElement(RouterView, { ...props }) : null);
return App;
}
const { componentName: layoutName, props: layoutProps } = layoutConfig;
const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {};
const sectionalRender = this.isSectionalRender();
if (!sectionalRender && Layout) {
App = (props: any) =>
createElement(
Layout,
{ ...layoutProps, ...extraLayoutProps },
RouterView ? createElement(RouterView, props) : null,
);
} else {
App = (props: any) => (RouterView ? createElement(RouterView, props) : null);
}
return App;
}
runApp(App: any, config: any) {
ReactDOM.render(<App />, document.getElementById(config?.containerId || 'App'));
}
// 内置实现 for 动态化渲染
getRouterView(): ReactType | null {
const routerConfig = this.getRouterConfig();
if (!routerConfig) {
return null;
}
const routes: Array<{
path: string;
children: any;
exact: boolean;
defined: { keepAlive: boolean; [key: string]: any };
}> = [];
let homePageId = this.getHomePage();
Object.keys(routerConfig).forEach((pageId: string, idx: number) => {
if (!pageId) {
return;
}
const path = routerConfig[pageId];
routes.push({
path,
children: (props: any) => this.getLazyComponent(pageId, props),
exact: true,
defined: { keepAlive: true },
});
if (homePageId) {
return;
}
if (idx === 0 || path === '/') {
homePageId = pageId;
}
});
if (homePageId) {
routes.push({
path: '**',
children: (props: any) => this.getLazyComponent(homePageId, { ...props }),
exact: true,
defined: { keepAlive: true },
});
}
const RouterView = (props: any) => {
return createElement(Router as any, {
routes,
components: this.getComponents(),
utils: this.getUtils(),
componentsMap: this.getComponentsMapObj(),
...props,
});
};
return RouterView;
}
getLazyComponent(pageId: string, props: any): ReactElement | null {
if (!pageId) {
return null;
}
if (this.getlazyElement(pageId)) {
return this.getlazyElement(pageId);
} else {
const lazyElement = createElement(LazyComponent as any, {
getPageData: async () => await this.getPageData(pageId),
key: pageId,
...props,
});
this.setlazyElement(pageId, lazyElement);
return lazyElement;
}
}
}

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "lib"
},
"include": [
"./src/"
]
}