diff --git a/packages/rax-provider/CHANGELOG.md b/packages/rax-provider/CHANGELOG.md new file mode 100644 index 000000000..e9fb6ecf5 --- /dev/null +++ b/packages/rax-provider/CHANGELOG.md @@ -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. \ No newline at end of file diff --git a/packages/rax-provider/README.md b/packages/rax-provider/README.md new file mode 100644 index 000000000..f37b9b0f6 --- /dev/null +++ b/packages/rax-provider/README.md @@ -0,0 +1 @@ +# 低代码引擎运行时框架 diff --git a/packages/rax-provider/build.json b/packages/rax-provider/build.json new file mode 100644 index 000000000..3edf14380 --- /dev/null +++ b/packages/rax-provider/build.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "build-plugin-rax-component", + { + "type": "rax", + "targets": ["web"] + } + ] + ] +} diff --git a/packages/rax-provider/package.json b/packages/rax-provider/package.json new file mode 100644 index 000000000..62712f312 --- /dev/null +++ b/packages/rax-provider/package.json @@ -0,0 +1,30 @@ +{ + "name": "@ali/lowcode-rax-provider", + "version": "0.8.14-beta.0", + "description": "Rax Provider for Runtime", + "files": [ + "es", + "lib" + ], + "main": "lib/index.js", + "module": "es/index.js", + "scripts": { + "start": "build-scripts start", + "build": "build-scripts build" + }, + "license": "MIT", + "dependencies": { + "@ali/lowcode-runtime": "^0.8.14-beta.0", + "rax": "1.1.2", + "driver-universal": "^3.1.3", + "rax-use-router": "^3.0.0", + "history": "^4.10.1" + }, + "devDependencies": { + "@alib/build-scripts": "^0.1.18", + "build-plugin-rax-component": "^0.2.0" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + } +} diff --git a/packages/rax-provider/src/index.js b/packages/rax-provider/src/index.js new file mode 100644 index 000000000..e51321b80 --- /dev/null +++ b/packages/rax-provider/src/index.js @@ -0,0 +1,5 @@ +import RaxProvider from './provider'; +import getRouter from './router'; + +export { getRouter }; +export default RaxProvider; diff --git a/packages/rax-provider/src/lazy-component.js b/packages/rax-provider/src/lazy-component.js new file mode 100644 index 000000000..5430c75b9 --- /dev/null +++ b/packages/rax-provider/src/lazy-component.js @@ -0,0 +1,28 @@ +import { createElement, useState, useEffect } from 'rax'; +import { app } from '@ali/lowcode-runtime'; + +export default function LazyComponent(props) { + const [schema, setSchema] = useState(null); + + useEffect(() => { + (async () => { + const { getPageData } = props || {}; + if (getPageData && !schema) { + const data = await getPageData(); + setSchema(data); + } + })(); + }); + + const { getPageData, ...restProps } = props || {}; + const Renderer = app.getRenderer(); + const Loading = app.getLoading(); + if (!Renderer || !schema) { + if (!Loading) { + return null; + } + // loading扩展点 + return createElement(Loading); + } + return createElement(Renderer, { schema, loading: Loading ? createElement(Loading) : null, ...restProps }); +} diff --git a/packages/rax-provider/src/provider.js b/packages/rax-provider/src/provider.js new file mode 100644 index 000000000..b64b2316e --- /dev/null +++ b/packages/rax-provider/src/provider.js @@ -0,0 +1,103 @@ +import { createElement, render } from 'rax'; +import UniversalDriver from 'driver-universal'; +import { app, Provider } from '@ali/lowcode-runtime'; +import LazyComponent from './lazy-component'; +import getRouter from './router'; + +export default class RaxProvider extends Provider { + // 定制构造根组件的逻辑,如切换路由机制 + createApp() { + const RouterView = this.getRouterView(); + let App; + const layoutConfig = this.getLayoutConfig(); + if (!layoutConfig || !layoutConfig.componentName) { + App = (props) => (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) => + createElement( + Layout, + { ...layoutProps, ...extraLayoutProps }, + RouterView ? createElement(RouterView, props) : null, + ); + } else { + App = (props) => (RouterView ? createElement(RouterView, props) : null); + } + return App; + } + + runApp(App, config) { + render(createElement(App), document.getElementById(config?.containerId || 'App'), { driver: UniversalDriver }); + } + + // 内置实现 for 动态化渲染 + getRouterView() { + const routerConfig = this.getRouterConfig(); + if (!routerConfig) { + return null; + } + const routes = []; + let homePageId = this.getHomePage(); + Object.keys(routerConfig).forEach((pageId, idx) => { + if (!pageId) { + return; + } + const path = routerConfig[pageId]; + routes.push({ + path, + component: (props: any) => + this.getLazyComponent(pageId, { + components: this.getComponents(), + utils: this.getUtils(), + componentsMap: this.getComponentsMapObj(), + ...props, + }), + }); + if (homePageId) { + return; + } + if (idx === 0 || path === '/') { + homePageId = pageId; + } + }); + if (homePageId) { + routes.push({ + path: '**', + component: (props) => + this.getLazyComponent(homePageId, { + components: this.getComponents(), + utils: this.getUtils(), + componentsMap: this.getComponentsMapObj(), + ...props, + }), + }); + } + const Router = getRouter({ + history: this.getHistory(), + routes, + }); + const RouterView = (props) => createElement(Router, props); + return RouterView; + } + + getLazyComponent(pageId, props) { + if (!pageId) { + return null; + } + if (this.getlazyElement(pageId)) { + return this.getlazyElement(pageId); + } + const lazyElement = createElement(LazyComponent, { + // eslint-disable-next-line no-return-await + getPageData: async () => await this.getPageData(pageId), + key: pageId, + ...props, + }); + this.setlazyElement(pageId, lazyElement); + return lazyElement; + } +} diff --git a/packages/rax-provider/src/router.js b/packages/rax-provider/src/router.js new file mode 100644 index 000000000..5f2ffaba4 --- /dev/null +++ b/packages/rax-provider/src/router.js @@ -0,0 +1,26 @@ +import { useRouter } from 'rax-use-router'; +import { createHashHistory, createBrowserHistory } from 'history'; + +const getConfig = (config) => { + let { history } = config; + const { routes } = config; + if (typeof history === 'string') { + if (history === 'hash') { + history = createHashHistory(); + } else if (history === 'browser') { + history = createBrowserHistory(); + } + } + return () => ({ + history, + routes, + }); +}; + +export default function getRouter(config) { + return function Router() { + const configWrapper = getConfig(config); + const { component } = useRouter(configWrapper); + return component; + }; +}