diff --git a/packages/runtime-framework/.editorconfig b/packages/runtime-framework/.editorconfig new file mode 100644 index 000000000..16a029ac9 --- /dev/null +++ b/packages/runtime-framework/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Tab indentation +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/packages/runtime-framework/.eslintignore b/packages/runtime-framework/.eslintignore new file mode 100644 index 000000000..1fb2edf7c --- /dev/null +++ b/packages/runtime-framework/.eslintignore @@ -0,0 +1,6 @@ +.idea/ +.vscode/ +build/ +.* +~* +node_modules diff --git a/packages/runtime-framework/.eslintrc b/packages/runtime-framework/.eslintrc new file mode 100644 index 000000000..db78d35d1 --- /dev/null +++ b/packages/runtime-framework/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/@recore/config/.eslintrc" +} diff --git a/packages/runtime-framework/.gitignore b/packages/runtime-framework/.gitignore new file mode 100644 index 000000000..a3f292fcc --- /dev/null +++ b/packages/runtime-framework/.gitignore @@ -0,0 +1,41 @@ +node_modules/ +coverage/ +build/ +dist/ +.idea/ +.vscode/ +.theia/ +.recore/ +demo/ +~* +package-lock.json + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.Trash* +*.swp +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db diff --git a/packages/runtime-framework/.prettierrc b/packages/runtime-framework/.prettierrc new file mode 100644 index 000000000..8748c5ed3 --- /dev/null +++ b/packages/runtime-framework/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "singleQuote": true, + "printWidth": 120, + "trailingComma": "all" +} diff --git a/packages/runtime-framework/README.md b/packages/runtime-framework/README.md index 12e6d0a3b..f37b9b0f6 100644 --- a/packages/runtime-framework/README.md +++ b/packages/runtime-framework/README.md @@ -1 +1 @@ -运行时框架 +# 低代码引擎运行时框架 diff --git a/packages/runtime-framework/index.d.ts b/packages/runtime-framework/index.d.ts new file mode 100644 index 000000000..5988aa400 --- /dev/null +++ b/packages/runtime-framework/index.d.ts @@ -0,0 +1,25 @@ +import { ReactType } from 'react'; + +export as namespace LowCodeEngineRuntime; +export = LowCodeEngineRuntime; + +declare module LowCodeEngineRuntime { + type HistoryMode = 'browser' | 'hash'; + + interface ComponentsMap { + [key: string]: ReactType; + } + + interface UtilsMap { + [key: string]: any; + } + + interface AppConfig { + history?: HistoryMode; + globalComponents?: ComponentsMap; + globalUtils?: UtilsMap; + containerId?: string; + } + + function runApp(Component: any, config?: AppConfig | (() => AppConfig), exposeModule?: boolean): any; +} \ No newline at end of file diff --git a/packages/runtime-framework/package.json b/packages/runtime-framework/package.json new file mode 100644 index 000000000..225792897 --- /dev/null +++ b/packages/runtime-framework/package.json @@ -0,0 +1,31 @@ +{ + "name": "@ali/lowcode-engine-runtime", + "version": "0.0.1", + "description": "runtime for Ali lowCode engine", + "main": "lib/index.js", + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + }, + "files": [ + "lib" + ], + "scripts": { + "build": "tsc", + "test": "ava", + "test:snapshot": "ava --update-snapshots" + }, + "ava": { + "compileEnhancements": false, + "snapshotDir": "test/fixtures/__snapshots__", + "extensions": [ + "ts" + ], + "require": [ + "ts-node/register" + ] + }, + "license": "MIT", + "dependencies": { + "@ali/recore": "^1.6.9" + } +} diff --git a/packages/runtime-framework/src/boot.ts b/packages/runtime-framework/src/boot.ts new file mode 100644 index 000000000..2598b18fe --- /dev/null +++ b/packages/runtime-framework/src/boot.ts @@ -0,0 +1,44 @@ +import { ComponentClass, FunctionComponent } from 'react'; + +type TComponent = ComponentClass | FunctionComponent; + +class Trunk { + private renderer: TComponent | null = null; + private layouts: { [key: string]: TComponent } = {}; + private loading: TComponent | null = null; + + public registerRenderer(renderer: TComponent): any { + this.renderer = renderer; + } + + public registerLayout(componentName: string, Layout: TComponent): any { + if (!componentName || !Layout) { + return; + } + this.layouts[componentName] = Layout; + } + + public registerLoading(component: TComponent) { + if (!component) { + return; + } + this.loading = component; + } + + public getLayout(componentName: string) { + if (!componentName) { + return; + } + return this.layouts[componentName]; + } + + public getRenderer(): TComponent | null { + return this.renderer; + } + + public getLoading(): TComponent | null { + return this.loading; + } +} + +export default new Trunk(); diff --git a/packages/runtime-framework/src/index.ts b/packages/runtime-framework/src/index.ts new file mode 100644 index 000000000..37abfe968 --- /dev/null +++ b/packages/runtime-framework/src/index.ts @@ -0,0 +1,5 @@ +import { navigator, Router, runApp as run } from '@ali/recore'; +import Boot from './boot'; +import Provider from './provider'; + +export { run, Router, Boot, Provider, navigator }; diff --git a/packages/runtime-framework/src/lazyComponent.tsx b/packages/runtime-framework/src/lazyComponent.tsx new file mode 100644 index 000000000..9acd799ce --- /dev/null +++ b/packages/runtime-framework/src/lazyComponent.tsx @@ -0,0 +1,43 @@ +import { Component, createElement } from 'react'; +import Boot from './boot'; + +interface IProps { + getPageData: () => any; + [key: string]: any; +} + +interface IState { + schema: object | null; +} + +export default class LazyComponent extends Component { + constructor(props: IProps) { + super(props); + this.state = { + schema: null, + }; + } + + public async componentDidMount() { + const { getPageData } = this.props; + if (getPageData && !this.state.schema) { + const schema = await getPageData(); + this.setState({ schema }); + } + } + + public render() { + const { getPageData, ...restProps } = this.props; + const { schema } = this.state; + const Renderer = Boot.getRenderer(); + const Loading = Boot.getLoading(); + if (!Renderer || !schema) { + if (!Loading) { + return null; + } + // loading扩展点 + return createElement(Loading); + } + return createElement(Renderer as any, { schema, ...restProps }); + } +} diff --git a/packages/runtime-framework/src/provider.ts b/packages/runtime-framework/src/provider.ts new file mode 100644 index 000000000..b0535d89d --- /dev/null +++ b/packages/runtime-framework/src/provider.ts @@ -0,0 +1,89 @@ +import { createElement, ReactElement, ReactType } from 'react'; +import LazyComponent from './lazyComponent'; + +export interface IAppData { + App: any; + config: object; +} + +interface IComponentsMap { + [key: string]: ReactType; +} + +interface IUtilsMap { + [key: string]: any; +} + +type HistoryMode = 'browser' | 'hash'; + +export interface IAppConfig { + history?: HistoryMode; + globalComponents?: IComponentsMap; + globalUtils?: IUtilsMap; + containerId?: string; +} + +export default abstract class Provider { + public globalComponents: any = {}; + public globalUtils: any = {}; + public routerConfig: { [key: string]: string } = {}; + public layout: { componentName: string; props: any } | null = null; + private lazyElementsMap: { [key: string]: any } = {}; + + constructor() { + this.init(); + } + + public create(appkey: string): Promise { + return new Promise(async (resolve, reject) => { + try { + const config = await this.getAppData(appkey); + const App = this.createApp(); + resolve({ + App, + config, + }); + } catch (err) { + reject(err.message); + } + }); + } + + public async init() { + console.log('init'); + } + + public async getAppData(appkey: string, restOptions?: any): Promise { + console.log('getAppData'); + return {}; + } + + public async getPageData(pageId: string, restOptions?: any): Promise { + console.log('getPageData'); + return; + } + + public getLazyComponent(pageId: string, props: any): ReactElement | null { + if (!pageId) { + return null; + } + if (this.lazyElementsMap[pageId]) { + console.log('缓存'); + return this.lazyElementsMap[pageId]; + } else { + const lazyElement = createElement(LazyComponent as any, { + getPageData: async () => await this.getPageData(pageId), + key: pageId, + ...props, + }); + this.lazyElementsMap[pageId] = lazyElement; + console.log('新组件'); + return lazyElement; + } + } + + public createApp() { + console.log('createApp'); + return; + } +} diff --git a/packages/runtime-framework/test/foobar.ts b/packages/runtime-framework/test/foobar.ts new file mode 100644 index 000000000..7a14c4b2d --- /dev/null +++ b/packages/runtime-framework/test/foobar.ts @@ -0,0 +1,5 @@ +import test from 'ava'; + +test('foobar', t => { + t.pass(); +}); diff --git a/packages/runtime-framework/tsconfig.json b/packages/runtime-framework/tsconfig.json new file mode 100644 index 000000000..be9a486b2 --- /dev/null +++ b/packages/runtime-framework/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./lib", + "jsx": "react", + } +} \ No newline at end of file