chore: 抽离React

This commit is contained in:
wuyue.xht 2020-05-18 16:03:44 +08:00
parent 0e50a2056a
commit 8e361967e0
9 changed files with 53 additions and 203 deletions

View File

@ -1,9 +1,5 @@
{
"plugins": [
"build-plugin-component",
"build-plugin-fusion",
["build-plugin-moment-locales", {
"locales": ["zh-cn"]
}]
"build-plugin-component"
]
}

View File

@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-runtime",
"version": "0.8.12",
"version": "0.8.14",
"description": "Runtime for Ali lowCode engine",
"files": [
"es",
@ -25,15 +25,13 @@
},
"license": "MIT",
"dependencies": {
"@ali/recore": "^1.6.9",
"@ali/offline-events": "^1.0.0"
"@ali/offline-events": "^1.0.0",
"history": "^4.10.1"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
"@types/node": "^13.7.1",
"@types/react": "^16",
"@types/react-dom": "^16",
"build-plugin-component": "^0.2.11"
"build-plugin-component": "^0.2.16"
},
"publishConfig": {
"registry": "https://registry.npm.alibaba-inc.com"

View File

@ -1,4 +1,3 @@
import { ReactType } from 'react';
import Provider from './provider';
export interface ILayoutOptions {
@ -7,16 +6,16 @@ export interface ILayoutOptions {
}
export default class Container {
private renderer: ReactType | null = null;
private layouts: { [key: string]: { content: ReactType; props: any } } = {};
private loading: ReactType | null = null;
private renderer: any = null;
private layouts: { [key: string]: { content: any; props: any } } = {};
private loading: any = null;
private provider: any;
registerRenderer(renderer: ReactType): any {
registerRenderer(renderer: any): any {
this.renderer = renderer;
}
registerLayout(Layout: ReactType, options: ILayoutOptions): any {
registerLayout(Layout: any, options: ILayoutOptions): any {
if (!options) {
return;
}
@ -27,7 +26,7 @@ export default class Container {
this.layouts[componentName] = { content: Layout, props };
}
registerLoading(component: ReactType) {
registerLoading(component: any) {
if (!component) {
return;
}
@ -50,11 +49,11 @@ export default class Container {
return this.layouts[componentName];
}
getRenderer(): ReactType | null {
getRenderer(): any {
return this.renderer;
}
getLoading(): ReactType | null {
getLoading(): any {
return this.loading;
}

View File

@ -1,7 +1,6 @@
import { ReactType } from 'react';
import Container, { ILayoutOptions } from './container';
import { IProvider } from './provider';
import run from './run';
import runApp from './runApp';
class App {
private container: Container;
@ -11,18 +10,18 @@ class App {
}
run() {
run();
runApp();
}
registerRenderer(renderer: ReactType): any {
registerRenderer(renderer: any): any {
this.container.registerRenderer(renderer);
}
registerLayout(Layout: ReactType, options: ILayoutOptions): any {
registerLayout(Layout: any, options: ILayoutOptions): any {
this.container.registerLayout(Layout, options);
}
registerLoading(component: ReactType) {
registerLoading(component: any) {
this.container.registerLoading(component);
}
@ -34,11 +33,11 @@ class App {
return this.container.getLayout(componentName);
}
getRenderer(): ReactType | null {
getRenderer(): any | null {
return this.container.getRenderer();
}
getLoading(): ReactType | null {
getLoading(): any | null {
return this.container.getLoading();
}

View File

@ -1,4 +1,4 @@
import { IAppConfig, IUtils, IComponents, HistoryMode } from '../run';
import { IAppConfig, IUtils, IComponents, HistoryMode } from './runApp';
import EventEmitter from '@ali/offline-events';
interface IConstants {
@ -110,6 +110,7 @@ export interface IProvider {
getPageData(pageId: string): Promise<ComponentModel | undefined>;
getLazyComponent(pageId: string, props: any): any;
createApp(): void;
runApp(App: any, config: IAppConfig): void;
}
export default class Provider implements IProvider {
@ -197,6 +198,10 @@ export default class Provider implements IProvider {
throw new Error('Method called "createApp" not implemented.');
}
runApp(App: any, config: IAppConfig) {
throw new Error('Method called "runApp" not implemented.');
}
registerComponents(components: IComponents | undefined) {
if (!components) {
return;

View File

@ -1,100 +0,0 @@
import { createElement, ReactType, ReactElement } from 'react';
import { Router } from '@ali/recore';
import app from '../../index';
import Provider from '..';
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;
}
// 内置实现 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

@ -1,43 +0,0 @@
import { Component, createElement } from 'react';
import app from '../../index';
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

@ -1,6 +1,4 @@
import { ReactType } from 'react';
import { runApp } from '@ali/recore';
import { HashHistoryBuildOptions, BrowserHistoryBuildOptions, MemoryHistoryBuildOptions } from '@recore/history';
import { HashHistoryBuildOptions, BrowserHistoryBuildOptions, MemoryHistoryBuildOptions } from 'history';
import app from './index';
export type HistoryOptions = {
@ -8,7 +6,7 @@ export type HistoryOptions = {
} & (HashHistoryBuildOptions | BrowserHistoryBuildOptions | MemoryHistoryBuildOptions);
export interface IComponents {
[key: string]: ReactType;
[key: string]: any;
}
export interface IUtils {
@ -22,34 +20,35 @@ export interface IAppConfig {
components?: IComponents;
utils?: IUtils;
containerId?: string;
[key: string]: any;
}
export interface IRecoreAppConfig {
history?: HistoryMode;
globalComponents?: IComponents;
globalUtils?: IUtils;
containerId?: string;
}
// export interface IRecoreAppConfig {
// history?: HistoryMode;
// globalComponents?: IComponents;
// globalUtils?: IUtils;
// containerId?: string;
// }
function transformConfig(config: IAppConfig | (() => IAppConfig)): IRecoreAppConfig {
if (!config) {
return {};
}
if (typeof config === 'function') {
config = config();
}
return {
history: config.history,
globalComponents: config.components,
globalUtils: config.utils,
containerId: config.containerId,
};
}
// function transformConfig(config: IAppConfig | (() => IAppConfig)): IRecoreAppConfig {
// if (!config) {
// return {};
// }
// if (typeof config === 'function') {
// config = config();
// }
// return {
// history: config.history,
// globalComponents: config.components,
// globalUtils: config.utils,
// containerId: config.containerId,
// };
// }
export default function run() {
export default function runApp() {
const provider = app.getProvider();
if (!provider) {
throw new Error('');
throw new Error('Please register class Provider');
}
provider.onReady(() => {
const promise = provider.async();
@ -58,8 +57,7 @@ export default function run() {
return;
}
const App = provider.createApp();
config = transformConfig(config);
runApp(App, config);
provider.runApp(App, config);
});
});
}

View File

@ -1,7 +1,5 @@
import { navigator, Router } from '@ali/recore';
import Provider from './core/provider';
import ReactProvider from './core/provider/react';
import app from './core';
import * as Utils from './utils';
export { app, Router, Provider, ReactProvider, navigator, Utils };
export { app, Provider, Utils };