mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 17:48:13 +00:00
refactor: 重构runtime
This commit is contained in:
parent
ec3a979bca
commit
55948e1d3f
@ -3,6 +3,105 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
<a name="1.0.6-0"></a>
|
||||
## [1.0.6-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@1.0.5-0...@ali/lowcode-react-provider@1.0.6-0) (2020-08-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 增加错误边界&pageReady钩子 ([3bb2fc1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3bb2fc1))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.0.5-0"></a>
|
||||
## [1.0.5-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@1.0.4-0...@ali/lowcode-react-provider@1.0.5-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="1.0.4-0"></a>
|
||||
## [1.0.4-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@1.0.3-0...@ali/lowcode-react-provider@1.0.4-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="1.0.3-0"></a>
|
||||
## [1.0.3-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@1.0.2-0...@ali/lowcode-react-provider@1.0.3-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="1.0.2-0"></a>
|
||||
## [1.0.2-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@1.0.1-0...@ali/lowcode-react-provider@1.0.2-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="1.0.1-0"></a>
|
||||
## [1.0.1-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@1.0.0...@ali/lowcode-react-provider@1.0.1-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="1.0.0"></a>
|
||||
# [1.0.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@0.13.0...@ali/lowcode-react-provider@1.0.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="0.13.0"></a>
|
||||
# [0.13.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@0.12.0...@ali/lowcode-react-provider@0.13.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="0.12.0"></a>
|
||||
# [0.12.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@0.10.0...@ali/lowcode-react-provider@0.12.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="0.11.0"></a>
|
||||
# [0.11.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@0.10.0...@ali/lowcode-react-provider@0.11.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="0.10.0"></a>
|
||||
# [0.10.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@0.9.0...@ali/lowcode-react-provider@0.10.0) (2020-08-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="0.9.0"></a>
|
||||
# [0.9.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@0.8.16...@ali/lowcode-react-provider@0.9.0) (2020-08-14)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-react-provider
|
||||
|
||||
<a name="0.8.16"></a>
|
||||
## [0.8.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-react-provider@0.8.15...@ali/lowcode-react-provider@0.8.16) (2020-06-23)
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "@ali/lowcode-react-provider",
|
||||
"version": "0.8.16",
|
||||
"private": true,
|
||||
"version": "1.0.6-0",
|
||||
"description": "React Provider for Runtime",
|
||||
"files": [
|
||||
"es",
|
||||
@ -26,7 +25,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ali/lowcode-runtime": "^0.8.16",
|
||||
"@ali/lowcode-runtime": "^1.0.6-0",
|
||||
"@recore/router": "^1.0.11",
|
||||
"react": "^16",
|
||||
"react-dom": "^16"
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
import { Component } from 'react';
|
||||
import { app, Provider } from '@ali/lowcode-runtime';
|
||||
|
||||
interface IProps {
|
||||
getPageData: () => any;
|
||||
context: Provider;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
schema: object | null;
|
||||
hasError: boolean;
|
||||
}
|
||||
|
||||
export default class LazyComponent extends Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
schema: null,
|
||||
hasError: false,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromError() {
|
||||
return { hasError: true };
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const { getPageData, context } = this.props;
|
||||
if (getPageData && !this.state.schema) {
|
||||
try {
|
||||
const schema = await getPageData();
|
||||
this.setState({ schema });
|
||||
context.emitPageReady();
|
||||
} catch (error) {
|
||||
this.setState({ hasError: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
const { afterCatch } = app.getErrorBoundary() || {};
|
||||
if (typeof afterCatch === 'function') {
|
||||
afterCatch.call(this, error, errorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { schema, hasError } = this.state;
|
||||
if (hasError) {
|
||||
const { fallbackUI: ErrorView } = app.getErrorBoundary() || {};
|
||||
if (!ErrorView) {
|
||||
return '';
|
||||
}
|
||||
return <ErrorView />;
|
||||
}
|
||||
|
||||
const { getPageData, ...restProps } = this.props;
|
||||
const Renderer = app.getRenderer();
|
||||
const Loading = app.getLoading();
|
||||
if (!Renderer || !schema) {
|
||||
if (!Loading) {
|
||||
return null;
|
||||
}
|
||||
// loading扩展点
|
||||
return <Loading />;
|
||||
}
|
||||
return (
|
||||
<Renderer
|
||||
schema={schema}
|
||||
loading={Loading ? <Loading /> : null}
|
||||
{...restProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
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 });
|
||||
}
|
||||
}
|
||||
@ -2,13 +2,13 @@ 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';
|
||||
import LazyComponent from './components/LazyComponent';
|
||||
|
||||
export default class ReactProvider extends Provider {
|
||||
// 定制构造根组件的逻辑,如切换路由机制
|
||||
createApp() {
|
||||
const RouterView = this.getRouterView();
|
||||
let App;
|
||||
let RouterView = this.getRouterView();
|
||||
let App: any;
|
||||
const layoutConfig = this.getLayoutConfig();
|
||||
if (!layoutConfig || !layoutConfig.componentName) {
|
||||
App = (props: any) => (RouterView ? createElement(RouterView, { ...props }) : null);
|
||||
@ -16,7 +16,7 @@ export default class ReactProvider extends Provider {
|
||||
}
|
||||
const { componentName: layoutName, props: layoutProps } = layoutConfig;
|
||||
const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {};
|
||||
const sectionalRender = this.isSectionalRender();
|
||||
const sectionalRender = this.isSectionalRender;
|
||||
if (!sectionalRender && Layout) {
|
||||
App = (props: any) =>
|
||||
createElement(
|
||||
@ -31,14 +31,21 @@ export default class ReactProvider extends Provider {
|
||||
}
|
||||
|
||||
runApp(App: any, config: any) {
|
||||
ReactDOM.render(<App />, document.getElementById(config?.containerId || 'App'));
|
||||
const containerId = config?.containerId || 'App';
|
||||
let container = document.getElementById(containerId);
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
container.id = containerId;
|
||||
}
|
||||
ReactDOM.render(<App />, container);
|
||||
}
|
||||
|
||||
// 内置实现 for 动态化渲染
|
||||
getRouterView(): ReactType | null {
|
||||
getRouterView(): ReactType {
|
||||
const routerConfig = this.getRouterConfig();
|
||||
if (!routerConfig) {
|
||||
return null;
|
||||
return () => null;
|
||||
}
|
||||
const routes: Array<{
|
||||
path: string;
|
||||
@ -89,15 +96,16 @@ export default class ReactProvider extends Provider {
|
||||
if (!pageId) {
|
||||
return null;
|
||||
}
|
||||
if (this.getlazyElement(pageId)) {
|
||||
return this.getlazyElement(pageId);
|
||||
if (this.getLazyElement(pageId)) {
|
||||
return this.getLazyElement(pageId);
|
||||
} else {
|
||||
const lazyElement = createElement(LazyComponent as any, {
|
||||
getPageData: async () => await this.getPageData(pageId),
|
||||
key: pageId,
|
||||
context: this,
|
||||
...props,
|
||||
});
|
||||
this.setlazyElement(pageId, lazyElement);
|
||||
this.setLazyElement(pageId, lazyElement);
|
||||
return lazyElement;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,114 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
<a name="1.0.6-0"></a>
|
||||
## [1.0.6-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@1.0.5-0...@ali/lowcode-runtime@1.0.6-0) (2020-08-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 取消Provider的校验 ([a1755f2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a1755f2))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 兼容通过api更新属性的场景 ([b58d59b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b58d59b))
|
||||
* 增加错误边界&pageReady钩子 ([3bb2fc1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3bb2fc1))
|
||||
* 增加若干钩子方法 ([eb55712](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eb55712))
|
||||
* 支持多个provider ([642c62e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/642c62e))
|
||||
* 支持多个Provider ([e35357f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e35357f))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.0.5-0"></a>
|
||||
## [1.0.5-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@1.0.4-0...@ali/lowcode-runtime@1.0.5-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="1.0.4-0"></a>
|
||||
## [1.0.4-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@1.0.3-0...@ali/lowcode-runtime@1.0.4-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="1.0.3-0"></a>
|
||||
## [1.0.3-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@1.0.2-0...@ali/lowcode-runtime@1.0.3-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="1.0.2-0"></a>
|
||||
## [1.0.2-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@1.0.1-0...@ali/lowcode-runtime@1.0.2-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="1.0.1-0"></a>
|
||||
## [1.0.1-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@1.0.0...@ali/lowcode-runtime@1.0.1-0) (2020-08-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="1.0.0"></a>
|
||||
# [1.0.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@0.13.0...@ali/lowcode-runtime@1.0.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="0.13.0"></a>
|
||||
# [0.13.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@0.12.0...@ali/lowcode-runtime@0.13.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="0.12.0"></a>
|
||||
# [0.12.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@0.10.0...@ali/lowcode-runtime@0.12.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="0.11.0"></a>
|
||||
# [0.11.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@0.10.0...@ali/lowcode-runtime@0.11.0) (2020-08-17)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="0.10.0"></a>
|
||||
# [0.10.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@0.9.0...@ali/lowcode-runtime@0.10.0) (2020-08-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="0.9.0"></a>
|
||||
# [0.9.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@0.8.13...@ali/lowcode-runtime@0.9.0) (2020-08-14)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-runtime
|
||||
|
||||
<a name="0.8.16"></a>
|
||||
## [0.8.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-runtime@0.8.13...@ali/lowcode-runtime@0.8.16) (2020-06-23)
|
||||
|
||||
|
||||
18
packages/runtime/index.d.ts
vendored
18
packages/runtime/index.d.ts
vendored
@ -1,18 +0,0 @@
|
||||
type HistoryMode = 'browser' | 'hash';
|
||||
|
||||
interface ComponentsMap {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface UtilsMap {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface AppConfig {
|
||||
history?: HistoryMode;
|
||||
globalComponents?: ComponentsMap;
|
||||
globalUtils?: UtilsMap;
|
||||
containerId?: string;
|
||||
}
|
||||
|
||||
export function run(Component: any, config?: AppConfig | (() => AppConfig)): any;
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ali/lowcode-runtime",
|
||||
"version": "0.8.16",
|
||||
"version": "1.0.6-0",
|
||||
"description": "Runtime for Ali lowCode engine",
|
||||
"files": [
|
||||
"es",
|
||||
|
||||
@ -5,11 +5,17 @@ export interface ILayoutOptions {
|
||||
props?: any;
|
||||
}
|
||||
|
||||
export interface IErrorBoundaryConfig {
|
||||
fallbackUI: any;
|
||||
afterCatch?: (...rest: any) => any
|
||||
}
|
||||
|
||||
export default class Container {
|
||||
private renderer: any = null;
|
||||
private layouts: { [key: string]: { content: any; props: any } } = {};
|
||||
private loading: any = null;
|
||||
private provider: any;
|
||||
private errorBoundary: IErrorBoundaryConfig = { fallbackUI: () => '', afterCatch: () => {} };
|
||||
private providers: { [key: string]: Provider; } = {};
|
||||
|
||||
registerRenderer(renderer: any): any {
|
||||
this.renderer = renderer;
|
||||
@ -33,12 +39,19 @@ export default class Container {
|
||||
this.loading = component;
|
||||
}
|
||||
|
||||
registerErrorBoundary(config: IErrorBoundaryConfig) {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
this.errorBoundary = config;
|
||||
}
|
||||
|
||||
registerProvider(CustomProvider: any) {
|
||||
if (Provider.isPrototypeOf(CustomProvider)) {
|
||||
this.provider = new CustomProvider();
|
||||
} else {
|
||||
const identifier = (CustomProvider && CustomProvider.name) || 'registered Provider';
|
||||
throw new Error(`${identifier} is not a child class of Provider`);
|
||||
try {
|
||||
const p = new CustomProvider();
|
||||
this.providers[p.getContainerId()] = p;
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +70,19 @@ export default class Container {
|
||||
return this.loading;
|
||||
}
|
||||
|
||||
getProvider() {
|
||||
return this.provider;
|
||||
getErrorBoundary(): any {
|
||||
return this.errorBoundary;
|
||||
}
|
||||
|
||||
getProvider(id?: string) {
|
||||
if (!id) {
|
||||
for (const key in this.providers) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.providers, key)) {
|
||||
return this.providers[key];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this.providers[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,49 +1,383 @@
|
||||
import Container, { ILayoutOptions } from './container';
|
||||
import { IProvider } from './provider';
|
||||
import runApp from './runApp';
|
||||
import { IAppConfig, IUtils, IComponents, HistoryMode } from './runApp';
|
||||
import EventEmitter from '@ali/offline-events';
|
||||
|
||||
class App {
|
||||
private container: Container;
|
||||
|
||||
constructor() {
|
||||
this.container = new Container();
|
||||
}
|
||||
|
||||
run() {
|
||||
runApp();
|
||||
}
|
||||
|
||||
registerRenderer(renderer: any): any {
|
||||
this.container.registerRenderer(renderer);
|
||||
}
|
||||
|
||||
registerLayout(Layout: any, options: ILayoutOptions): any {
|
||||
this.container.registerLayout(Layout, options);
|
||||
}
|
||||
|
||||
registerLoading(component: any) {
|
||||
this.container.registerLoading(component);
|
||||
}
|
||||
|
||||
registerProvider(CustomProvider: any) {
|
||||
this.container.registerProvider(CustomProvider);
|
||||
}
|
||||
|
||||
getLayout(componentName: string) {
|
||||
return this.container.getLayout(componentName);
|
||||
}
|
||||
|
||||
getRenderer(): any | null {
|
||||
return this.container.getRenderer();
|
||||
}
|
||||
|
||||
getLoading(): any | null {
|
||||
return this.container.getLoading();
|
||||
}
|
||||
|
||||
getProvider(): IProvider {
|
||||
return this.container.getProvider();
|
||||
}
|
||||
interface IConstants {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export default new App();
|
||||
interface IComponentMap {
|
||||
componentName: string;
|
||||
package?: string;
|
||||
version?: string;
|
||||
destructuring?: boolean;
|
||||
exportName?: string;
|
||||
subName?: string;
|
||||
}
|
||||
|
||||
interface ILayoutConfig {
|
||||
componentName: string;
|
||||
props: any;
|
||||
}
|
||||
|
||||
interface IRouterConfig {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface IHistoryConfig {
|
||||
mode: HistoryMode;
|
||||
basement?: string;
|
||||
}
|
||||
|
||||
export interface IAppData {
|
||||
history?: HistoryMode;
|
||||
layout?: ILayoutConfig;
|
||||
routes?: IRouterConfig;
|
||||
containerId?: string;
|
||||
components?: IComponents;
|
||||
componentsMap?: IComponentMap[];
|
||||
utils?: IUtils;
|
||||
constants?: IConstants;
|
||||
i18n?: I18n;
|
||||
}
|
||||
|
||||
export interface ComponentProps {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface JSExpression {
|
||||
type: string;
|
||||
value: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface DataSourceItem {
|
||||
id: string;
|
||||
isInit: boolean;
|
||||
type: string;
|
||||
options: {
|
||||
uri: string;
|
||||
params: object;
|
||||
method: string;
|
||||
shouldFetch?: string;
|
||||
willFetch?: string;
|
||||
fit?: string;
|
||||
didFetch?: string;
|
||||
};
|
||||
dataHandler: JSExpression;
|
||||
}
|
||||
|
||||
export interface DataSource {
|
||||
list: DataSourceItem[];
|
||||
dataHandler: JSExpression;
|
||||
}
|
||||
|
||||
export interface LifeCycles {
|
||||
[key: string]: JSExpression;
|
||||
}
|
||||
|
||||
export interface Methods {
|
||||
[key: string]: JSExpression;
|
||||
}
|
||||
|
||||
export interface ComponentModel {
|
||||
id?: string;
|
||||
componentName: string;
|
||||
fileName?: string;
|
||||
props?: ComponentProps;
|
||||
css?: string;
|
||||
dataSource?: DataSource;
|
||||
lifeCycles?: LifeCycles;
|
||||
methods?: Methods;
|
||||
children?: ComponentModel[] | string[];
|
||||
condition?: JSExpression | boolean;
|
||||
loop?: string[];
|
||||
loopArgs?: string[];
|
||||
}
|
||||
|
||||
export interface I18n {
|
||||
'zh-CN': { [key: string]: string };
|
||||
'en-US': { [key: string]: string };
|
||||
}
|
||||
|
||||
type Locale = 'zh-CN' | 'en-US';
|
||||
|
||||
export default class Provider {
|
||||
emitter: EventEmitter = new EventEmitter();
|
||||
components: IComponents = {};
|
||||
utils: IUtils = {};
|
||||
constants: IConstants = {};
|
||||
routes: IRouterConfig | null = null;
|
||||
layout: ILayoutConfig | null = null;
|
||||
componentsMap: IComponentMap[] = [];
|
||||
history: HistoryMode = 'hash';
|
||||
containerId = '';
|
||||
i18n: I18n | null = null;
|
||||
homePage = '';
|
||||
lazyElementsMap: { [key: string]: any } = {};
|
||||
isSectionalRender = false;
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
async(): Promise<IAppConfig> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const appData: IAppData = await this.getAppData();
|
||||
if (!appData) {
|
||||
return;
|
||||
}
|
||||
const { history, layout, routes, containerId, components, componentsMap, utils, constants, i18n } = appData;
|
||||
this.setHistory(history);
|
||||
this.setLayoutConfig(layout);
|
||||
this.setRouterConfig(routes);
|
||||
this.setContainerId(containerId);
|
||||
this.setI18n(i18n);
|
||||
this.registerComponents(components);
|
||||
this.registerComponentsMap(componentsMap);
|
||||
this.registerUtils(utils);
|
||||
this.registerContants(constants);
|
||||
resolve({
|
||||
history: this.getHistory(),
|
||||
components: this.getComponents(),
|
||||
utils: this.getUtils(),
|
||||
containerId: this.getContainerId(),
|
||||
});
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
// 默认 ready,当重载了init时需手动触发 this.ready()
|
||||
this.ready();
|
||||
}
|
||||
|
||||
ready(params?: any) {
|
||||
if (params && typeof params === 'function') {
|
||||
params = params();
|
||||
}
|
||||
this.emitter.emit('ready', params || '');
|
||||
}
|
||||
|
||||
onReady(cb: (params?: any) => void) {
|
||||
if (!cb || typeof cb !== 'function') {
|
||||
return;
|
||||
}
|
||||
this.emitter.on('ready', cb);
|
||||
}
|
||||
|
||||
emitPageReady() {
|
||||
this.emitter.emit('pageReady');
|
||||
}
|
||||
|
||||
emitPageEnter() {
|
||||
this.emitter.emit('pageEnter');
|
||||
}
|
||||
|
||||
emitPageUpdate() {
|
||||
this.emitter.emit('pageUpdate');
|
||||
}
|
||||
|
||||
emitPageLeave() {
|
||||
this.emitter.emit('pageLeave');
|
||||
}
|
||||
|
||||
onPageReady(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageReady', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageReady', cb);
|
||||
};
|
||||
}
|
||||
|
||||
onPageEnter(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageEnter', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageEnter', cb);
|
||||
};
|
||||
}
|
||||
|
||||
onPageUpdate(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageUpdate', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageUpdate', cb);
|
||||
};
|
||||
}
|
||||
|
||||
onPageLeave(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageLeave', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageLeave', cb);
|
||||
};
|
||||
}
|
||||
|
||||
getAppData(): any {
|
||||
throw new Error('Method called "getAppData" not implemented.');
|
||||
}
|
||||
|
||||
getPageData(pageId?: string): any {
|
||||
throw new Error('Method called "getPageData" not implemented.');
|
||||
}
|
||||
|
||||
getLazyComponent(pageId: string, props: any): any {
|
||||
throw new Error('Method called "getLazyComponent" not implemented.');
|
||||
}
|
||||
|
||||
// 定制构造根组件的逻辑,如切换路由机制
|
||||
createApp() {
|
||||
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;
|
||||
}
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
registerComponentsMap(componentsMap: IComponentMap[] | undefined) {
|
||||
if (!componentsMap) {
|
||||
return;
|
||||
}
|
||||
this.componentsMap = componentsMap;
|
||||
}
|
||||
|
||||
registerUtils(utils: IUtils | undefined) {
|
||||
if (!utils) {
|
||||
return;
|
||||
}
|
||||
this.utils = utils;
|
||||
}
|
||||
|
||||
registerContants(constants: IConstants | undefined) {
|
||||
if (!constants) {
|
||||
return;
|
||||
}
|
||||
this.constants = constants;
|
||||
}
|
||||
|
||||
setLayoutConfig(config: ILayoutConfig | undefined) {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
this.layout = config;
|
||||
}
|
||||
|
||||
setRouterConfig(config: IRouterConfig | undefined) {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
this.routes = config;
|
||||
}
|
||||
|
||||
setHistory(config: HistoryMode | undefined): any {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
this.history = config;
|
||||
}
|
||||
|
||||
setContainerId(id: string | undefined) {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
this.containerId = id;
|
||||
}
|
||||
|
||||
setI18n(i18n: I18n | undefined) {
|
||||
if (!i18n) {
|
||||
return;
|
||||
}
|
||||
this.i18n = i18n;
|
||||
}
|
||||
|
||||
setLazyElement(pageId: string, cache: any) {
|
||||
if (!pageId || !cache) {
|
||||
return;
|
||||
}
|
||||
this.lazyElementsMap[pageId] = cache;
|
||||
}
|
||||
|
||||
setHomePage(pageId: string) {
|
||||
if (pageId) {
|
||||
this.homePage = pageId;
|
||||
}
|
||||
}
|
||||
|
||||
getComponents() {
|
||||
return this.components;
|
||||
}
|
||||
|
||||
getComponent(name: string) {
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
return this.components[name];
|
||||
}
|
||||
|
||||
getUtils() {
|
||||
return this.utils;
|
||||
}
|
||||
|
||||
getConstants() {
|
||||
return this.constants;
|
||||
}
|
||||
|
||||
getComponentsMap() {
|
||||
return this.componentsMap;
|
||||
}
|
||||
|
||||
getComponentsMapObj() {
|
||||
const compMapArr = this.getComponentsMap();
|
||||
if (!compMapArr || !Array.isArray(compMapArr)) {
|
||||
return;
|
||||
}
|
||||
const compMapObj: any = {};
|
||||
compMapArr.forEach((item: IComponentMap) => {
|
||||
if (!item || !item.componentName) {
|
||||
return;
|
||||
}
|
||||
compMapObj[item.componentName] = item;
|
||||
});
|
||||
return compMapObj;
|
||||
}
|
||||
|
||||
getLayoutConfig() {
|
||||
return this.layout;
|
||||
}
|
||||
|
||||
getRouterConfig() {
|
||||
return this.routes;
|
||||
}
|
||||
|
||||
getHistory() {
|
||||
return this.history;
|
||||
}
|
||||
|
||||
getContainerId() {
|
||||
return this.containerId || 'App';
|
||||
}
|
||||
|
||||
getI18n(locale?: Locale) {
|
||||
if (!this.i18n) {
|
||||
return;
|
||||
}
|
||||
return locale ? this.i18n[locale] : this.i18n;
|
||||
}
|
||||
|
||||
getHomePage() {
|
||||
return this.homePage;
|
||||
}
|
||||
|
||||
getLazyElement(pageId: string) {
|
||||
if (!pageId) {
|
||||
return;
|
||||
}
|
||||
return this.lazyElementsMap[pageId];
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,32 +101,20 @@ export interface I18n {
|
||||
|
||||
type Locale = 'zh-CN' | 'en-US';
|
||||
|
||||
export interface IProvider {
|
||||
init(): void;
|
||||
ready(): void;
|
||||
onReady(cb: any): void;
|
||||
async(): Promise<IAppConfig>;
|
||||
getAppData(): Promise<IAppData | undefined>;
|
||||
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 {
|
||||
private components: IComponents = {};
|
||||
private utils: IUtils = {};
|
||||
private constants: IConstants = {};
|
||||
private routes: IRouterConfig | null = null;
|
||||
private layout: ILayoutConfig | null = null;
|
||||
private componentsMap: IComponentMap[] = [];
|
||||
private history: HistoryMode = 'hash';
|
||||
private containerId = '';
|
||||
private i18n: I18n | null = null;
|
||||
private homePage = '';
|
||||
private lazyElementsMap: { [key: string]: any } = {};
|
||||
private sectionalRender = false;
|
||||
private emitter: EventEmitter = new EventEmitter();
|
||||
export default class Provider {
|
||||
emitter: EventEmitter = new EventEmitter();
|
||||
components: IComponents = {};
|
||||
utils: IUtils = {};
|
||||
constants: IConstants = {};
|
||||
routes: IRouterConfig | null = null;
|
||||
layout: ILayoutConfig | null = null;
|
||||
componentsMap: IComponentMap[] = [];
|
||||
history: HistoryMode = 'hash';
|
||||
containerId = '';
|
||||
i18n: I18n | null = null;
|
||||
homePage = '';
|
||||
lazyElementsMap: { [key: string]: any } = {};
|
||||
isSectionalRender = false;
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
@ -150,19 +138,18 @@ export default class Provider implements IProvider {
|
||||
this.registerUtils(utils);
|
||||
this.registerContants(constants);
|
||||
resolve({
|
||||
history,
|
||||
components,
|
||||
utils,
|
||||
containerId,
|
||||
history: this.getHistory(),
|
||||
components: this.getComponents(),
|
||||
utils: this.getUtils(),
|
||||
containerId: this.getContainerId(),
|
||||
});
|
||||
} catch (err) {
|
||||
reject(err.message);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
console.log('init');
|
||||
// 默认 ready,当重载了init时需手动触发 this.ready()
|
||||
this.ready();
|
||||
}
|
||||
@ -181,6 +168,50 @@ export default class Provider implements IProvider {
|
||||
this.emitter.on('ready', cb);
|
||||
}
|
||||
|
||||
emitPageReady() {
|
||||
this.emitter.emit('pageReady');
|
||||
}
|
||||
|
||||
emitPageEnter() {
|
||||
this.emitter.emit('pageEnter');
|
||||
}
|
||||
|
||||
emitPageUpdate() {
|
||||
this.emitter.emit('pageUpdate');
|
||||
}
|
||||
|
||||
emitPageLeave() {
|
||||
this.emitter.emit('pageLeave');
|
||||
}
|
||||
|
||||
onPageReady(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageReady', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageReady', cb);
|
||||
};
|
||||
}
|
||||
|
||||
onPageEnter(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageEnter', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageEnter', cb);
|
||||
};
|
||||
}
|
||||
|
||||
onPageUpdate(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageUpdate', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageUpdate', cb);
|
||||
};
|
||||
}
|
||||
|
||||
onPageLeave(cb: (params?: any) => void) {
|
||||
this.emitter.on('pageLeave', cb);
|
||||
return () => {
|
||||
this.emitter.removeListener('pageLeave', cb);
|
||||
};
|
||||
}
|
||||
|
||||
getAppData(): any {
|
||||
throw new Error('Method called "getAppData" not implemented.');
|
||||
}
|
||||
@ -244,7 +275,7 @@ export default class Provider implements IProvider {
|
||||
this.routes = config;
|
||||
}
|
||||
|
||||
setHistory(config: HistoryMode | undefined) {
|
||||
setHistory(config: HistoryMode | undefined): any {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
@ -265,7 +296,7 @@ export default class Provider implements IProvider {
|
||||
this.i18n = i18n;
|
||||
}
|
||||
|
||||
setlazyElement(pageId: string, cache: any) {
|
||||
setLazyElement(pageId: string, cache: any) {
|
||||
if (!pageId || !cache) {
|
||||
return;
|
||||
}
|
||||
@ -278,10 +309,6 @@ export default class Provider implements IProvider {
|
||||
}
|
||||
}
|
||||
|
||||
setSectionalRender() {
|
||||
this.sectionalRender = true;
|
||||
}
|
||||
|
||||
getComponents() {
|
||||
return this.components;
|
||||
}
|
||||
@ -333,7 +360,7 @@ export default class Provider implements IProvider {
|
||||
}
|
||||
|
||||
getContainerId() {
|
||||
return this.containerId;
|
||||
return this.containerId || 'App';
|
||||
}
|
||||
|
||||
getI18n(locale?: Locale) {
|
||||
@ -347,14 +374,10 @@ export default class Provider implements IProvider {
|
||||
return this.homePage;
|
||||
}
|
||||
|
||||
getlazyElement(pageId: string) {
|
||||
getLazyElement(pageId: string) {
|
||||
if (!pageId) {
|
||||
return;
|
||||
}
|
||||
return this.lazyElementsMap[pageId];
|
||||
}
|
||||
|
||||
isSectionalRender() {
|
||||
return this.sectionalRender;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ export interface IUtils {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type HistoryMode = 'browser' | 'hash';
|
||||
export type HistoryMode = 'browser' | 'hash' | 'BROWSER' | 'HASH';
|
||||
|
||||
export interface IAppConfig {
|
||||
history?: HistoryMode;
|
||||
@ -36,6 +36,13 @@ export default function runApp() {
|
||||
}
|
||||
const App = provider.createApp();
|
||||
provider.runApp(App, config);
|
||||
}).catch((err) => {
|
||||
console.error(err.message);
|
||||
const { fallbackUI } = app.getErrorBoundary() || {};
|
||||
if (!fallbackUI) {
|
||||
return;
|
||||
}
|
||||
provider.runApp(fallbackUI, {});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import Provider from './core/provider';
|
||||
import app from './core';
|
||||
import * as Utils from './utils';
|
||||
|
||||
export { app, Provider, Utils };
|
||||
export { app, Provider };
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
function isESModule(obj: any): obj is { [key: string]: any } {
|
||||
return obj && obj.__esModule;
|
||||
}
|
||||
|
||||
function accessLibrary(library: string | object) {
|
||||
if (typeof library !== 'string') {
|
||||
return library;
|
||||
}
|
||||
|
||||
return (window as any)[library];
|
||||
}
|
||||
|
||||
function getSubComponent(library: any, paths: string[]) {
|
||||
const l = paths.length;
|
||||
if (l < 1 || !library) {
|
||||
return library;
|
||||
}
|
||||
let i = 0;
|
||||
let component: any;
|
||||
while (i < l) {
|
||||
const key = paths[i]!;
|
||||
let ex: any;
|
||||
try {
|
||||
component = library[key];
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
component = null;
|
||||
}
|
||||
if (i === 0 && component == null && key === 'default') {
|
||||
if (ex) {
|
||||
return l === 1 ? library : null;
|
||||
}
|
||||
component = library;
|
||||
} else if (component == null) {
|
||||
return null;
|
||||
}
|
||||
library = component;
|
||||
i++;
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
function findComponent(libraryMap: LibraryMap, componentName: string, npm?: NpmInfo) {
|
||||
if (!npm) {
|
||||
return accessLibrary(componentName);
|
||||
}
|
||||
// libraryName the key access to global
|
||||
// export { exportName } from xxx exportName === global.libraryName.exportName
|
||||
// export exportName from xxx exportName === global.libraryName.default || global.libraryName
|
||||
// export { exportName as componentName } from package
|
||||
// if exportName == null exportName === componentName;
|
||||
// const componentName = exportName.subName, if exportName empty subName donot use
|
||||
const exportName = npm.exportName || npm.componentName || componentName;
|
||||
const libraryName = libraryMap[npm.package] || exportName;
|
||||
const library = accessLibrary(libraryName);
|
||||
const paths = npm.exportName && npm.subName ? npm.subName.split('.') : [];
|
||||
if (npm.destructuring) {
|
||||
paths.unshift(exportName);
|
||||
} else if (isESModule(library)) {
|
||||
paths.unshift('default');
|
||||
}
|
||||
return getSubComponent(library, paths);
|
||||
}
|
||||
|
||||
export interface LibraryMap {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface NpmInfo {
|
||||
componentName?: string;
|
||||
package: string;
|
||||
version: string;
|
||||
destructuring?: boolean;
|
||||
exportName?: string;
|
||||
subName?: string;
|
||||
main?: string;
|
||||
}
|
||||
|
||||
export function buildComponents(
|
||||
libraryMap: LibraryMap,
|
||||
componentsMap: { [componentName: string]: NpmInfo } | NpmInfo[],
|
||||
) {
|
||||
const components: any = {};
|
||||
if (componentsMap && Array.isArray(componentsMap)) {
|
||||
const compMapObj: any = {};
|
||||
componentsMap.forEach((item: NpmInfo) => {
|
||||
if (!item || !item.componentName) {
|
||||
return;
|
||||
}
|
||||
compMapObj[item.componentName] = item;
|
||||
});
|
||||
componentsMap = compMapObj;
|
||||
}
|
||||
Object.keys(componentsMap).forEach((componentName) => {
|
||||
const component = findComponent(libraryMap, componentName, (componentsMap as any)[componentName]);
|
||||
if (component) {
|
||||
components[componentName] = component;
|
||||
}
|
||||
});
|
||||
return components;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from './assets';
|
||||
Loading…
x
Reference in New Issue
Block a user