diff --git a/packages/demo/build.json b/packages/demo/build.json
index 48cdb5e94..452a15dca 100644
--- a/packages/demo/build.json
+++ b/packages/demo/build.json
@@ -1,7 +1,8 @@
{
"entry": {
- "index": "src/index.jsx",
- "react-simulator-renderer": "../react-simulator-renderer/src/index.js"
+ "index": "src/index.ts",
+ "react-simulator-renderer": "../react-simulator-renderer/src/index.ts",
+ "preview": "src/preview.ts"
},
"vendor": false,
"devServer": {
diff --git a/packages/demo/cloud-build.json b/packages/demo/cloud-build.json
index 16a6afe1d..7b4fcd1d9 100644
--- a/packages/demo/cloud-build.json
+++ b/packages/demo/cloud-build.json
@@ -1,6 +1,7 @@
{
"entry": {
- "lowcode-demo": "src/index.jsx"
+ "lowcode-editor": "src/index.ts",
+ "lowcode-preview": "src/preview.ts"
},
"vendor": false,
"externals": {
diff --git a/packages/demo/package.json b/packages/demo/package.json
index 6e448fffe..0b5e31cb8 100644
--- a/packages/demo/package.json
+++ b/packages/demo/package.json
@@ -18,8 +18,11 @@
"@ali/lowcode-plugin-zh-en": "^0.8.0",
"@ali/lowcode-plugin-sample-logo": "^0.8.0",
"@ali/lowcode-plugin-sample-preview": "^0.8.0",
+ "@ali/lowcode-runtime": "^0.8.0",
+ "@ali/lowcode-react-renderer": "^0.8.0",
"@alife/theme-lowcode-dark": "^0.1.0",
"@alife/theme-lowcode-light": "^0.1.0",
+ "@alifd/next": "^1.19.21",
"react": "^16.8.1",
"react-dom": "^16.8.1"
},
diff --git a/packages/demo/public/preview.html b/packages/demo/public/preview.html
new file mode 100644
index 000000000..34c8cf86c
--- /dev/null
+++ b/packages/demo/public/preview.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ LowCodeEngine DEMO
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/demo/src/app/config/app.js b/packages/demo/src/app/config/app.js
new file mode 100644
index 000000000..c1ad5b57c
--- /dev/null
+++ b/packages/demo/src/app/config/app.js
@@ -0,0 +1,21 @@
+export default {
+ sdkVersion: '1.0.3',
+ historyMode: 'hash', // 浏览器路由:brower 哈希路由:hash
+ constainerId: 'app',
+ layout: {
+ componentName: 'BasicLayout',
+ props: {
+ name: '低代码引擎预览 demo',
+ logo: {
+ src: 'https://img.alicdn.com/tfs/TB1kAfWyrY1gK0jSZTEXXXDQVXa-75-33.png',
+ width: 40,
+ height: 20,
+ },
+ },
+ },
+ theme: {
+ package: '@alife/theme-fusion',
+ version: '^0.1.0',
+ },
+ compDependencies: [],
+};
diff --git a/packages/demo/src/app/config/components.js b/packages/demo/src/app/config/components.js
new file mode 100644
index 000000000..91aef7993
--- /dev/null
+++ b/packages/demo/src/app/config/components.js
@@ -0,0 +1,12 @@
+/**
+ * 内置组件
+ */
+import Engine from '@ali/iceluna-sdk/lib/engine';
+import Page from '@ali/iceluna-sdk/lib/engine/pageEngine'
+import Div from '@ali/iceluna-comp-div';
+
+export default {
+ Engine,
+ Page,
+ Div,
+}
diff --git a/packages/demo/src/app/config/componentsMap.js b/packages/demo/src/app/config/componentsMap.js
new file mode 100644
index 000000000..a9bb73edb
--- /dev/null
+++ b/packages/demo/src/app/config/componentsMap.js
@@ -0,0 +1,53 @@
+export default {
+ Button: {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Button',
+ },
+ 'Button.Group': {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Button',
+ subName: 'Group',
+ },
+ Input: {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Input',
+ },
+ Form: {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Form',
+ },
+ 'Form.Item': {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Form',
+ subName: 'Item',
+ },
+ NumberPicker: {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'NumberPicker',
+ },
+ Select: {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Select',
+ },
+ 'Select.Option': {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Select',
+ subName: 'Option',
+ },
+};
diff --git a/packages/demo/src/config/utils.js b/packages/demo/src/app/config/utils.js
similarity index 100%
rename from packages/demo/src/config/utils.js
rename to packages/demo/src/app/config/utils.js
diff --git a/packages/demo/src/app/index.ts b/packages/demo/src/app/index.ts
new file mode 100644
index 000000000..2cfc99a6b
--- /dev/null
+++ b/packages/demo/src/app/index.ts
@@ -0,0 +1,22 @@
+import { boot, run } from '@ali/lowcode-runtime';
+import Renderer from '@ali/lowcode-react-renderer';
+import FusionLoading from './plugins/loading/fusion';
+import BasicLayout from './layouts/BasicLayout';
+import provider from './plugins/provider';
+
+// 注册渲染模块
+boot.registerRenderer(Renderer);
+
+// 注册布局组件,可注册多个
+boot.registerLayout('BasicLayout', BasicLayout);
+
+// 注册页面 Loading
+boot.registerLoading(FusionLoading);
+
+const appProvider = provider.create('lowcode_demo'); // 入参为应用唯一标识
+
+// 异步加载应用配置
+appProvider.then(({ App, config }) => {
+ // 启动应用
+ run(App, config);
+});
diff --git a/packages/demo/src/app/layouts/BasicLayout/index.js b/packages/demo/src/app/layouts/BasicLayout/index.js
new file mode 100644
index 000000000..6a51fdc75
--- /dev/null
+++ b/packages/demo/src/app/layouts/BasicLayout/index.js
@@ -0,0 +1,27 @@
+import { Search, Icon, Shell } from '@alifd/next';
+import './index.less';
+
+// eslint-disable-next-line react/prop-types
+export default ({ name, children, logo }) => (
+
+
+
+ {name}
+
+
+
+
+
+
+
+ MyName
+
+
+ {children}
+
+
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+
+);
diff --git a/packages/demo/src/app/layouts/BasicLayout/index.less b/packages/demo/src/app/layouts/BasicLayout/index.less
new file mode 100644
index 000000000..000abd1c8
--- /dev/null
+++ b/packages/demo/src/app/layouts/BasicLayout/index.less
@@ -0,0 +1,24 @@
+@header-height: 52px;
+
+.avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ vertical-align: middle;
+}
+
+.basic-shell {
+ min-height: 100vh;
+ .next-shell-header {
+ height: @header-height;
+ }
+ .next-shell-main {
+ flex: 1;
+ display: flex;
+ flex-flow: column;
+ min-height: calc(100% - @header-height);
+ .next-shell-sub-main {
+ flex: 1;
+ }
+ }
+}
diff --git a/packages/demo/src/app/plugins/loading/deep/index.less b/packages/demo/src/app/plugins/loading/deep/index.less
new file mode 100644
index 000000000..2b59ea5ef
--- /dev/null
+++ b/packages/demo/src/app/plugins/loading/deep/index.less
@@ -0,0 +1,11 @@
+.recore-loading {
+ width: 48px;
+ height: 48px;
+ background: url(https://g.alicdn.com/uxcore/pic/loading.svg) center no-repeat;
+ background-size: contain;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ margin-top: -24px;
+ margin-left: -24px;
+}
diff --git a/packages/demo/src/app/plugins/loading/deep/index.tsx b/packages/demo/src/app/plugins/loading/deep/index.tsx
new file mode 100644
index 000000000..02b2fc692
--- /dev/null
+++ b/packages/demo/src/app/plugins/loading/deep/index.tsx
@@ -0,0 +1,3 @@
+import './index.less';
+
+export default () => ;
diff --git a/packages/demo/src/app/plugins/loading/fusion/index.less b/packages/demo/src/app/plugins/loading/fusion/index.less
new file mode 100644
index 000000000..0e53165cb
--- /dev/null
+++ b/packages/demo/src/app/plugins/loading/fusion/index.less
@@ -0,0 +1,9 @@
+.fusion-loading {
+ width: 48px;
+ height: 48px;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ margin-top: -24px;
+ margin-left: -24px;
+}
diff --git a/packages/demo/src/app/plugins/loading/fusion/index.tsx b/packages/demo/src/app/plugins/loading/fusion/index.tsx
new file mode 100644
index 000000000..e61bfd9f0
--- /dev/null
+++ b/packages/demo/src/app/plugins/loading/fusion/index.tsx
@@ -0,0 +1,4 @@
+import { Loading } from '@alifd/next';
+import './index.less';
+
+export default () => ;
diff --git a/packages/demo/src/app/plugins/provider.ts b/packages/demo/src/app/plugins/provider.ts
new file mode 100644
index 000000000..fc56ece03
--- /dev/null
+++ b/packages/demo/src/app/plugins/provider.ts
@@ -0,0 +1,114 @@
+import { createElement } from 'react';
+import { Provider, boot, Router } from '@ali/lowcode-runtime';
+import appConfig from '../config/app';
+import builtInComps from '../config/components';
+import componentsMap from '../config/componentsMap';
+import util from '../config/utils';
+import { buildComponents } from './utils';
+
+// 定制加载应用配置的逻辑
+class PreviewProvider extends Provider {
+ // 定制获取、处理应用配置(组件、插件、路由模式、布局等)的逻辑
+ async getAppData(appkey: string, restOptions?: any): Promise {
+ const { historyMode, layout, constainerId } = appConfig;
+ const appSchemaStr: any = localStorage.getItem('lce-dev-store');
+ const appSchema = JSON.parse(appSchemaStr || '');
+ const history = {
+ mode: historyMode || 'hash',
+ basement: '/',
+ };
+ this.layout = layout;
+ const routes: any = {};
+ appSchema.componentsTree.forEach((page: any, idx: number) => {
+ if (!page.fileName) {
+ return;
+ }
+ const pageId = page.fileName;
+ routes[pageId] = `/${pageId}`;
+ });
+ this.routerConfig = routes;
+ this.componentsMap = componentsMap;
+ this.globalComponents = { ...builtInComps, ...buildComponents({ '@alifd/next': 'Next' }, componentsMap) };
+ this.globalUtils = util;
+ return {
+ history,
+ globalComponents: this.globalComponents,
+ globalUtils: this.globalUtils,
+ constainerId,
+ };
+ }
+
+ // 定制获取、处理页面 schema 的逻辑
+ async getPageData(pageId: string, restOptions?: any) {
+ const appSchemaStr = localStorage.getItem('lce-dev-store');
+ const appSchema = JSON.parse(appSchemaStr || '');
+ const idx = appSchema.componentsTree.findIndex(
+ (page: any, idx: number) => (page.fileName || `page${idx}`) === pageId,
+ );
+ const schema = appSchema.componentsTree[idx];
+ return schema;
+ }
+
+ // 定制构造根组件的逻辑,如切换路由机制
+ createApp() {
+ if (!this.routerConfig) {
+ return;
+ }
+ const routes: Array<{ path: string; children: any; exact: boolean; keepAlive: boolean }> = [];
+ let homePageId = '';
+ Object.keys(this.routerConfig).forEach((pageId: string, idx: number) => {
+ if (!pageId) {
+ return;
+ }
+ const path = this.routerConfig[pageId];
+ if (idx === 0 || path === '/') {
+ homePageId = pageId;
+ }
+ routes.push({
+ path,
+ children: (props: any) => this.getLazyComponent(pageId, props),
+ exact: true,
+ keepAlive: true,
+ });
+ });
+ if (homePageId) {
+ routes.push({
+ path: '**',
+ children: (props: any) => this.getLazyComponent(homePageId, { ...props }),
+ exact: true,
+ keepAlive: true,
+ });
+ }
+ const RouterView = (props: any) => {
+ return createElement(Router as any, {
+ routes,
+ components: this.globalComponents,
+ utils: this.globalUtils,
+ componentsMap: this.componentsMap,
+ ...props,
+ });
+ };
+ let App;
+ if (!this.layout || !(this.layout as any).componentName) {
+ App = (props: any) => createElement(RouterView, { ...props });
+ return App;
+ }
+ const { componentName: layoutName, props: layoutProps } = this.layout as any;
+ const Layout = boot.getLayout(layoutName);
+ if (Layout) {
+ App = (props: any) =>
+ createElement(
+ Layout,
+ {
+ ...layoutProps,
+ },
+ RouterView({ props }),
+ );
+ } else {
+ App = (props: any) => createElement(RouterView, props);
+ }
+ return App;
+ }
+}
+
+export default new PreviewProvider();
diff --git a/packages/demo/src/app/plugins/utils.js b/packages/demo/src/app/plugins/utils.js
new file mode 100644
index 000000000..b65d4864e
--- /dev/null
+++ b/packages/demo/src/app/plugins/utils.js
@@ -0,0 +1,74 @@
+function isESModule(obj) {
+ return obj && obj.__esModule;
+}
+
+function getSubComponent(library, paths) {
+ const l = paths.length;
+ if (l < 1 || !library) {
+ return library;
+ }
+ let i = 0;
+ let component;
+ while (i < l) {
+ const key = paths[i];
+ let ex;
+ 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 accessLibrary(library) {
+ if (typeof library !== 'string') {
+ return library;
+ }
+
+ return window[library];
+}
+
+function findComponent(libraryMap, componentName, npm) {
+ 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 function buildComponents(libraryMap, componentsMap) {
+ const components = {};
+ Object.keys(componentsMap).forEach((componentName) => {
+ const component = findComponent(libraryMap, componentName, componentsMap[componentName]);
+ if (component) {
+ components[componentName] = component;
+ }
+ });
+ return components;
+}
diff --git a/packages/demo/src/config/components.js b/packages/demo/src/editor/config/components.js
similarity index 100%
rename from packages/demo/src/config/components.js
rename to packages/demo/src/editor/config/components.js
diff --git a/packages/demo/src/config/constants.js b/packages/demo/src/editor/config/constants.js
similarity index 100%
rename from packages/demo/src/config/constants.js
rename to packages/demo/src/editor/config/constants.js
diff --git a/packages/demo/src/config/skeleton.js b/packages/demo/src/editor/config/skeleton.js
similarity index 100%
rename from packages/demo/src/config/skeleton.js
rename to packages/demo/src/editor/config/skeleton.js
diff --git a/packages/demo/src/config/theme.scss b/packages/demo/src/editor/config/theme.scss
similarity index 100%
rename from packages/demo/src/config/theme.scss
rename to packages/demo/src/editor/config/theme.scss
diff --git a/packages/demo/src/editor/config/utils.js b/packages/demo/src/editor/config/utils.js
new file mode 100644
index 000000000..ff8b4c563
--- /dev/null
+++ b/packages/demo/src/editor/config/utils.js
@@ -0,0 +1 @@
+export default {};
diff --git a/packages/demo/src/global.scss b/packages/demo/src/editor/global.scss
similarity index 100%
rename from packages/demo/src/global.scss
rename to packages/demo/src/editor/global.scss
diff --git a/packages/demo/src/index.jsx b/packages/demo/src/editor/index.tsx
similarity index 96%
rename from packages/demo/src/index.jsx
rename to packages/demo/src/editor/index.tsx
index f666fe2c5..b229bec9b 100644
--- a/packages/demo/src/index.jsx
+++ b/packages/demo/src/editor/index.tsx
@@ -13,6 +13,7 @@ registerSetters();
const LCE_CONTAINER = document.getElementById('lce-container');
+console.info('aeafeawef')
if (!LCE_CONTAINER) {
throw new Error('当前页面不存在 节点.');
}
diff --git a/packages/demo/src/index.ts b/packages/demo/src/index.ts
new file mode 100644
index 000000000..27a6639b2
--- /dev/null
+++ b/packages/demo/src/index.ts
@@ -0,0 +1 @@
+import "./editor"
diff --git a/packages/demo/src/preview.js b/packages/demo/src/preview.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/demo/src/preview.ts b/packages/demo/src/preview.ts
new file mode 100644
index 000000000..168ff510c
--- /dev/null
+++ b/packages/demo/src/preview.ts
@@ -0,0 +1 @@
+import "./app";
diff --git a/packages/react-simulator-renderer/src/index.js b/packages/react-simulator-renderer/src/index.ts
similarity index 67%
rename from packages/react-simulator-renderer/src/index.js
rename to packages/react-simulator-renderer/src/index.ts
index 05be5384a..3a8872665 100644
--- a/packages/react-simulator-renderer/src/index.js
+++ b/packages/react-simulator-renderer/src/index.ts
@@ -1,7 +1,7 @@
import renderer from './renderer';
if (typeof window !== 'undefined') {
- window.SimulatorRenderer = renderer;
+ (window as any).SimulatorRenderer = renderer;
}
export default renderer;
diff --git a/packages/runtime/index.d.ts b/packages/runtime/index.d.ts
index 5988aa400..6e3013290 100644
--- a/packages/runtime/index.d.ts
+++ b/packages/runtime/index.d.ts
@@ -1,25 +1,19 @@
import { ReactType } from 'react';
+type HistoryMode = 'browser' | 'hash';
-export as namespace LowCodeEngineRuntime;
-export = LowCodeEngineRuntime;
+interface ComponentsMap {
+ [key: string]: ReactType;
+}
-declare module LowCodeEngineRuntime {
- type HistoryMode = 'browser' | 'hash';
+interface UtilsMap {
+ [key: string]: any;
+}
- interface ComponentsMap {
- [key: string]: ReactType;
- }
+export interface AppConfig {
+ history?: HistoryMode;
+ globalComponents?: ComponentsMap;
+ globalUtils?: UtilsMap;
+ containerId?: string;
+}
- 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
+export function run(Component: any, config?: AppConfig | (() => AppConfig)): any;
diff --git a/packages/runtime/src/boot.ts b/packages/runtime/src/boot.ts
index 2598b18fe..6b99987e1 100644
--- a/packages/runtime/src/boot.ts
+++ b/packages/runtime/src/boot.ts
@@ -7,36 +7,36 @@ class Trunk {
private layouts: { [key: string]: TComponent } = {};
private loading: TComponent | null = null;
- public registerRenderer(renderer: TComponent): any {
+ registerRenderer(renderer: TComponent): any {
this.renderer = renderer;
}
- public registerLayout(componentName: string, Layout: TComponent): any {
+ registerLayout(componentName: string, Layout: TComponent): any {
if (!componentName || !Layout) {
return;
}
this.layouts[componentName] = Layout;
}
- public registerLoading(component: TComponent) {
+ registerLoading(component: TComponent) {
if (!component) {
return;
}
this.loading = component;
}
- public getLayout(componentName: string) {
+ getLayout(componentName: string) {
if (!componentName) {
return;
}
return this.layouts[componentName];
}
- public getRenderer(): TComponent | null {
+ getRenderer(): TComponent | null {
return this.renderer;
}
- public getLoading(): TComponent | null {
+ getLoading(): TComponent | null {
return this.loading;
}
}
diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts
index 37abfe968..dc637c4be 100644
--- a/packages/runtime/src/index.ts
+++ b/packages/runtime/src/index.ts
@@ -1,5 +1,5 @@
import { navigator, Router, runApp as run } from '@ali/recore';
-import Boot from './boot';
+import boot from './boot';
import Provider from './provider';
-export { run, Router, Boot, Provider, navigator };
+export { run, Router, boot, Provider, navigator };
diff --git a/packages/runtime/src/lazyComponent.tsx b/packages/runtime/src/lazyComponent.tsx
index 9acd799ce..18a582241 100644
--- a/packages/runtime/src/lazyComponent.tsx
+++ b/packages/runtime/src/lazyComponent.tsx
@@ -1,5 +1,5 @@
import { Component, createElement } from 'react';
-import Boot from './boot';
+import boot from './boot';
interface IProps {
getPageData: () => any;
@@ -18,7 +18,7 @@ export default class LazyComponent extends Component {
};
}
- public async componentDidMount() {
+ async componentDidMount() {
const { getPageData } = this.props;
if (getPageData && !this.state.schema) {
const schema = await getPageData();
@@ -26,11 +26,11 @@ export default class LazyComponent extends Component {
}
}
- public render() {
+ render() {
const { getPageData, ...restProps } = this.props;
const { schema } = this.state;
- const Renderer = Boot.getRenderer();
- const Loading = Boot.getLoading();
+ const Renderer = boot.getRenderer();
+ const Loading = boot.getLoading();
if (!Renderer || !schema) {
if (!Loading) {
return null;
diff --git a/packages/runtime/src/provider.ts b/packages/runtime/src/provider.ts
index b0535d89d..9949e10c3 100644
--- a/packages/runtime/src/provider.ts
+++ b/packages/runtime/src/provider.ts
@@ -23,18 +23,19 @@ export interface IAppConfig {
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;
+export default class Provider {
+ globalComponents: any = {};
+ globalUtils: any = {};
+ routerConfig: { [key: string]: string } = {};
+ layout: { componentName: string; props: any } | null = null;
+ componentsMap: any = null;
private lazyElementsMap: { [key: string]: any } = {};
constructor() {
this.init();
}
- public create(appkey: string): Promise {
+ create(appkey: string): Promise {
return new Promise(async (resolve, reject) => {
try {
const config = await this.getAppData(appkey);
@@ -49,21 +50,21 @@ export default abstract class Provider {
});
}
- public async init() {
+ async init() {
console.log('init');
}
- public async getAppData(appkey: string, restOptions?: any): Promise