mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-13 12:13:10 +00:00
fix: fix renderer some bugs
This commit is contained in:
parent
ac8aa2c5a4
commit
a855c05d67
@ -34,13 +34,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alilc/lowcode-shared": "workspace:*",
|
"@alilc/lowcode-shared": "workspace:*",
|
||||||
"@alilc/lowcode-types": "workspace:*",
|
"lodash-es": "^4.17.21"
|
||||||
"@alilc/lowcode-utils": "workspace:*",
|
|
||||||
"@formatjs/intl": "^2.10.1",
|
|
||||||
"lodash-es": "^4.17.21",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"events": "^3.3.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
@ -49,8 +43,6 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@alilc/lowcode-shared": "workspace:*",
|
"@alilc/lowcode-shared": "workspace:*",
|
||||||
"@alilc/lowcode-types": "workspace:*",
|
|
||||||
"@alilc/lowcode-utils": "workspace:*",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,2 @@
|
|||||||
export * from './preference';
|
export * from './preference';
|
||||||
export * from './hotkey';
|
export * from './hotkey';
|
||||||
export * from './intl';
|
|
||||||
export * from './instantiation';
|
|
||||||
|
|||||||
@ -1,154 +0,0 @@
|
|||||||
import {
|
|
||||||
signal,
|
|
||||||
computed,
|
|
||||||
effect,
|
|
||||||
createLogger,
|
|
||||||
type Spec,
|
|
||||||
type Signal,
|
|
||||||
type ComputedSignal,
|
|
||||||
type PlainObject,
|
|
||||||
} from '@alilc/lowcode-shared';
|
|
||||||
import { createIntl, createIntlCache, type IntlShape as IntlFormatter } from '@formatjs/intl';
|
|
||||||
import { mapKeys } from 'lodash-es';
|
|
||||||
|
|
||||||
export { IntlFormatter };
|
|
||||||
|
|
||||||
const logger = createLogger({ level: 'warn', bizName: 'globalLocale' });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* todo: key 需要被统一
|
|
||||||
*/
|
|
||||||
const STORED_LOCALE_KEY = 'ali-lowcode-config';
|
|
||||||
|
|
||||||
export type Locale = string;
|
|
||||||
export type IntlMessage = Spec.I18nMap[Locale];
|
|
||||||
export type IntlMessageRecord = Spec.I18nMap;
|
|
||||||
|
|
||||||
export class Intl {
|
|
||||||
#locale: Signal<Locale>;
|
|
||||||
#messageStore: Signal<IntlMessageRecord>;
|
|
||||||
#currentMessage: ComputedSignal<IntlMessage>;
|
|
||||||
#intlShape: IntlFormatter;
|
|
||||||
|
|
||||||
constructor(defaultLocale?: string, messages: IntlMessageRecord = {}) {
|
|
||||||
if (defaultLocale) {
|
|
||||||
defaultLocale = nomarlizeLocale(defaultLocale);
|
|
||||||
} else {
|
|
||||||
defaultLocale = 'zh-CN';
|
|
||||||
}
|
|
||||||
|
|
||||||
const messageStore = mapKeys(messages, (_, key) => {
|
|
||||||
return nomarlizeLocale(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.#locale = signal(defaultLocale);
|
|
||||||
this.#messageStore = signal(messageStore);
|
|
||||||
this.#currentMessage = computed(() => {
|
|
||||||
return this.#messageStore.value[this.#locale.value] ?? {};
|
|
||||||
});
|
|
||||||
|
|
||||||
effect(() => {
|
|
||||||
const cache = createIntlCache();
|
|
||||||
this.#intlShape = createIntl(
|
|
||||||
{
|
|
||||||
locale: this.#locale.value,
|
|
||||||
messages: this.#currentMessage.value,
|
|
||||||
},
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocale() {
|
|
||||||
return this.#locale.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setLocale(locale: Locale) {
|
|
||||||
const nomarlizedLocale = nomarlizeLocale(locale);
|
|
||||||
this.#locale.value = nomarlizedLocale;
|
|
||||||
}
|
|
||||||
|
|
||||||
addMessages(locale: Locale, messages: IntlMessage) {
|
|
||||||
locale = nomarlizeLocale(locale);
|
|
||||||
const original = this.#messageStore.value[locale];
|
|
||||||
|
|
||||||
this.#messageStore.value[locale] = Object.assign(original, messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
getFormatter(): IntlFormatter {
|
|
||||||
return this.#intlShape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeLocale() {
|
|
||||||
let result: Locale | undefined;
|
|
||||||
|
|
||||||
let config: PlainObject = {};
|
|
||||||
try {
|
|
||||||
// store 1: config from storage
|
|
||||||
config = JSON.parse(localStorage.getItem(STORED_LOCALE_KEY) || '');
|
|
||||||
} catch {
|
|
||||||
// ignore;
|
|
||||||
}
|
|
||||||
if (config?.locale) {
|
|
||||||
result = (config.locale || '').replace('_', '-');
|
|
||||||
logger.debug(`getting locale from localStorage: ${result}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result && navigator.language) {
|
|
||||||
// store 2: config from system
|
|
||||||
result = nomarlizeLocale(navigator.language);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
logger.warn(
|
|
||||||
'something when wrong when trying to get locale, use zh-CN as default, please check it out!',
|
|
||||||
);
|
|
||||||
result = 'zh-CN';
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const navigatorLanguageMapping: Record<string, string> = {
|
|
||||||
en: 'en-US',
|
|
||||||
zh: 'zh-CN',
|
|
||||||
zt: 'zh-TW',
|
|
||||||
es: 'es-ES',
|
|
||||||
pt: 'pt-PT',
|
|
||||||
fr: 'fr-FR',
|
|
||||||
de: 'de-DE',
|
|
||||||
it: 'it-IT',
|
|
||||||
ru: 'ru-RU',
|
|
||||||
ja: 'ja-JP',
|
|
||||||
ko: 'ko-KR',
|
|
||||||
ar: 'ar-SA',
|
|
||||||
tr: 'tr-TR',
|
|
||||||
th: 'th-TH',
|
|
||||||
vi: 'vi-VN',
|
|
||||||
nl: 'nl-NL',
|
|
||||||
he: 'iw-IL',
|
|
||||||
id: 'in-ID',
|
|
||||||
pl: 'pl-PL',
|
|
||||||
hi: 'hi-IN',
|
|
||||||
uk: 'uk-UA',
|
|
||||||
ms: 'ms-MY',
|
|
||||||
tl: 'tl-PH',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* nomarlize navigator.language or user input's locale
|
|
||||||
* eg: zh -> zh-CN, zh_CN -> zh-CN, zh-cn -> zh-CN
|
|
||||||
* @param target
|
|
||||||
*/
|
|
||||||
function nomarlizeLocale(target: Locale) {
|
|
||||||
if (navigatorLanguageMapping[target]) {
|
|
||||||
return navigatorLanguageMapping[target];
|
|
||||||
}
|
|
||||||
|
|
||||||
const replaced = target.replace('_', '-');
|
|
||||||
const splited = replaced.split('-').slice(0, 2);
|
|
||||||
splited[1] = splited[1].toUpperCase();
|
|
||||||
|
|
||||||
return splited.join('-');
|
|
||||||
}
|
|
||||||
@ -1,22 +1,12 @@
|
|||||||
import { createRenderer, type AppOptions } from '@alilc/lowcode-renderer-core';
|
import { createRenderer } from '@alilc/lowcode-renderer-core';
|
||||||
import { type ComponentType } from 'react';
|
|
||||||
import { type Root, createRoot } from 'react-dom/client';
|
import { type Root, createRoot } from 'react-dom/client';
|
||||||
import { ApplicationView, RendererContext, boosts } from '../app';
|
import { type ReactAppOptions, RendererContext } from './context';
|
||||||
|
import { ApplicationView, boosts } from '../app';
|
||||||
export interface ReactAppOptions extends AppOptions {
|
|
||||||
faultComponent?: ComponentType<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createApp = async (options: ReactAppOptions) => {
|
export const createApp = async (options: ReactAppOptions) => {
|
||||||
return createRenderer(async (context) => {
|
return createRenderer(async (context) => {
|
||||||
const { schema, boostsManager } = context;
|
const { schema, boostsManager } = context;
|
||||||
|
|
||||||
// set config
|
|
||||||
// if (options.faultComponent) {
|
|
||||||
// context.config.set('faultComponent', options.faultComponent);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// extends boosts
|
|
||||||
boostsManager.extend(boosts.toExpose());
|
boostsManager.extend(boosts.toExpose());
|
||||||
|
|
||||||
let root: Root | undefined;
|
let root: Root | undefined;
|
||||||
@ -27,10 +17,11 @@ export const createApp = async (options: ReactAppOptions) => {
|
|||||||
|
|
||||||
const defaultId = schema.get('config')?.targetRootID ?? 'app';
|
const defaultId = schema.get('config')?.targetRootID ?? 'app';
|
||||||
const rootElement = normalizeContainer(containerOrId, defaultId);
|
const rootElement = normalizeContainer(containerOrId, defaultId);
|
||||||
|
const contextValue = { ...context, options };
|
||||||
|
|
||||||
root = createRoot(rootElement);
|
root = createRoot(rootElement);
|
||||||
root.render(
|
root.render(
|
||||||
<RendererContext.Provider value={context}>
|
<RendererContext.Provider value={contextValue}>
|
||||||
<ApplicationView />
|
<ApplicationView />
|
||||||
</RendererContext.Provider>,
|
</RendererContext.Provider>,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { createRenderer, type AppOptions } from '@alilc/lowcode-renderer-core';
|
import { createRenderer, type AppOptions } from '@alilc/lowcode-renderer-core';
|
||||||
import { FunctionComponent } from 'react';
|
import { FunctionComponent } from 'react';
|
||||||
import { type LowCodeComponentProps, createComponentBySchema } from '../runtime/schema';
|
import { type LowCodeComponentProps, createComponentBySchema } from '../runtime/schema';
|
||||||
import { RendererContext } from '../app/context';
|
import { RendererContext } from '../api/context';
|
||||||
|
|
||||||
interface Render {
|
interface Render {
|
||||||
toComponent(): FunctionComponent<LowCodeComponentProps>;
|
toComponent(): FunctionComponent<LowCodeComponentProps>;
|
||||||
@ -12,10 +12,11 @@ export async function createComponent(options: AppOptions) {
|
|||||||
const { schema } = context;
|
const { schema } = context;
|
||||||
|
|
||||||
const LowCodeComponent = createComponentBySchema(schema.get('componentsTree')[0]);
|
const LowCodeComponent = createComponentBySchema(schema.get('componentsTree')[0]);
|
||||||
|
const contextValue = { ...context, options };
|
||||||
|
|
||||||
function Component(props: LowCodeComponentProps) {
|
function Component(props: LowCodeComponentProps) {
|
||||||
return (
|
return (
|
||||||
<RendererContext.Provider value={context}>
|
<RendererContext.Provider value={contextValue}>
|
||||||
<LowCodeComponent {...props} />
|
<LowCodeComponent {...props} />
|
||||||
</RendererContext.Provider>
|
</RendererContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
14
packages/react-renderer/src/api/context.ts
Normal file
14
packages/react-renderer/src/api/context.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { type ComponentType, createContext, useContext } from 'react';
|
||||||
|
import { type AppOptions, type RenderContext } from '@alilc/lowcode-renderer-core';
|
||||||
|
|
||||||
|
export interface ReactAppOptions extends AppOptions {
|
||||||
|
faultComponent?: ComponentType<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RendererContext = createContext<RenderContext & { options: ReactAppOptions }>(
|
||||||
|
undefined!,
|
||||||
|
);
|
||||||
|
|
||||||
|
RendererContext.displayName = 'RendererContext';
|
||||||
|
|
||||||
|
export const useRendererContext = () => useContext(RendererContext);
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import { createContext, useContext } from 'react';
|
|
||||||
import { type RenderContext } from '@alilc/lowcode-renderer-core';
|
|
||||||
|
|
||||||
export const RendererContext = createContext<RenderContext>(undefined!);
|
|
||||||
|
|
||||||
RendererContext.displayName = 'RendererContext';
|
|
||||||
|
|
||||||
export const useRenderContext = () => useContext(RendererContext);
|
|
||||||
@ -1,3 +1,2 @@
|
|||||||
export * from './context';
|
|
||||||
export * from './boosts';
|
export * from './boosts';
|
||||||
export * from './view';
|
export * from './view';
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { useRenderContext } from './context';
|
import { useRendererContext } from '../api/context';
|
||||||
import { getComponentByName } from '../runtime/schema';
|
import { getComponentByName } from '../runtime/schema';
|
||||||
import { boosts } from './boosts';
|
import { boosts } from './boosts';
|
||||||
|
|
||||||
export function ApplicationView() {
|
export function ApplicationView() {
|
||||||
const renderContext = useRenderContext();
|
const rendererContext = useRendererContext();
|
||||||
const { schema } = renderContext;
|
const { schema } = rendererContext;
|
||||||
const appWrappers = boosts.getAppWrappers();
|
const appWrappers = boosts.getAppWrappers();
|
||||||
const Outlet = boosts.getOutlet();
|
const Outlet = boosts.getOutlet();
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ export function ApplicationView() {
|
|||||||
|
|
||||||
if (layoutConfig) {
|
if (layoutConfig) {
|
||||||
const componentName = layoutConfig.componentName;
|
const componentName = layoutConfig.componentName;
|
||||||
const Layout = getComponentByName(componentName, renderContext);
|
const Layout = getComponentByName(componentName, rendererContext);
|
||||||
|
|
||||||
if (Layout) {
|
if (Layout) {
|
||||||
const layoutProps: any = layoutConfig.props ?? {};
|
const layoutProps: any = layoutConfig.props ?? {};
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
export * from './api/app';
|
export * from './api/app';
|
||||||
export * from './api/component';
|
export * from './api/component';
|
||||||
export { useRenderContext, defineRendererPlugin } from './app';
|
export * from './api/context';
|
||||||
|
export { defineRendererPlugin } from './app';
|
||||||
export * from './router';
|
export * from './router';
|
||||||
|
export { LifecyclePhase } from '@alilc/lowcode-renderer-core';
|
||||||
|
|
||||||
export type { Spec, ProCodeComponent, LowCodeComponent } from '@alilc/lowcode-shared';
|
export type { Spec, ProCodeComponent, LowCodeComponent } from '@alilc/lowcode-shared';
|
||||||
export type { PackageLoader, CodeScope, Plugin } from '@alilc/lowcode-renderer-core';
|
export type { PackageLoader, CodeScope, Plugin } from '@alilc/lowcode-renderer-core';
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
export * from './context';
|
export * from './context';
|
||||||
export * from './plugin';
|
export * from './plugin';
|
||||||
export type { Router, RouterHistory } from '@alilc/lowcode-renderer-router';
|
export type * from '@alilc/lowcode-renderer-router';
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { defineRendererPlugin } from '../app/boosts';
|
import { defineRendererPlugin } from '../app/boosts';
|
||||||
import { LifecyclePhase } from '@alilc/lowcode-renderer-core';
|
|
||||||
import { createRouter, type RouterOptions } from '@alilc/lowcode-renderer-router';
|
import { createRouter, type RouterOptions } from '@alilc/lowcode-renderer-router';
|
||||||
import { createRouterView } from './routerView';
|
import { createRouterView } from './routerView';
|
||||||
import { RouteOutlet } from './route';
|
import { RouteOutlet } from './route';
|
||||||
@ -13,7 +12,7 @@ const defaultRouterOptions: RouterOptions = {
|
|||||||
export const routerPlugin = defineRendererPlugin({
|
export const routerPlugin = defineRendererPlugin({
|
||||||
name: 'rendererRouter',
|
name: 'rendererRouter',
|
||||||
async setup(context) {
|
async setup(context) {
|
||||||
const { whenLifeCylePhaseChange, schema, boosts } = context;
|
const { schema, boosts } = context;
|
||||||
|
|
||||||
let routerConfig = defaultRouterOptions;
|
let routerConfig = defaultRouterOptions;
|
||||||
|
|
||||||
@ -27,17 +26,14 @@ export const routerPlugin = defineRendererPlugin({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const router = createRouter(routerConfig);
|
const router = createRouter(routerConfig);
|
||||||
|
|
||||||
boosts.codeRuntime.getScope().set('router', router);
|
|
||||||
boosts.temporaryUse('router', router);
|
|
||||||
|
|
||||||
const RouterView = createRouterView(router);
|
const RouterView = createRouterView(router);
|
||||||
|
|
||||||
boosts.addAppWrapper(RouterView);
|
boosts.addAppWrapper(RouterView);
|
||||||
boosts.setOutlet(RouteOutlet);
|
boosts.setOutlet(RouteOutlet);
|
||||||
|
|
||||||
whenLifeCylePhaseChange(LifecyclePhase.AfterInitPackageLoad).then(() => {
|
boosts.codeRuntime.getScope().set('router', router);
|
||||||
return router.isReady();
|
boosts.temporaryUse('router', router);
|
||||||
});
|
|
||||||
|
await router.isReady();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useRenderContext } from '../app/context';
|
import { useRendererContext } from '../api/context';
|
||||||
import { OutletProps } from '../app/boosts';
|
import { OutletProps } from '../app/boosts';
|
||||||
import { useRouteLocation } from './context';
|
import { useRouteLocation } from './context';
|
||||||
import { createComponentBySchema } from '../runtime/schema';
|
import { createComponentBySchema } from '../runtime/schema';
|
||||||
|
|
||||||
export function RouteOutlet(props: OutletProps) {
|
export function RouteOutlet(props: OutletProps) {
|
||||||
const context = useRenderContext();
|
const context = useRendererContext();
|
||||||
const location = useRouteLocation();
|
const location = useRouteLocation();
|
||||||
const { schema, packageManager } = context;
|
const { schema, packageManager } = context;
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
type Spec,
|
type Spec,
|
||||||
} from '@alilc/lowcode-shared';
|
} from '@alilc/lowcode-shared';
|
||||||
import { type ComponentType, type ReactInstance, useMemo, createElement } from 'react';
|
import { type ComponentType, type ReactInstance, useMemo, createElement } from 'react';
|
||||||
import { useRenderContext } from '../app/context';
|
import { useRendererContext } from '../api/context';
|
||||||
import { useReactiveStore } from './hooks/useReactiveStore';
|
import { useReactiveStore } from './hooks/useReactiveStore';
|
||||||
import { useModel } from './context';
|
import { useModel } from './context';
|
||||||
import { getComponentByName } from './schema';
|
import { getComponentByName } from './schema';
|
||||||
@ -65,10 +65,10 @@ export function WidgetComponent(props: WidgetRendererProps) {
|
|||||||
const componentNode = widget.node as NormalizedComponentNode;
|
const componentNode = widget.node as NormalizedComponentNode;
|
||||||
const { ref, ...componentProps } = componentNode.props;
|
const { ref, ...componentProps } = componentNode.props;
|
||||||
|
|
||||||
const renderContext = useRenderContext();
|
const rendererContext = useRendererContext();
|
||||||
|
|
||||||
const Component = useMemo(
|
const Component = useMemo(
|
||||||
() => getComponentByName(componentNode.componentName, renderContext),
|
() => getComponentByName(componentNode.componentName, rendererContext),
|
||||||
[widget],
|
[widget],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -94,11 +94,16 @@ export function WidgetComponent(props: WidgetRendererProps) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const finalProps = {
|
||||||
|
...otherProps,
|
||||||
|
...state.props,
|
||||||
|
};
|
||||||
|
|
||||||
return createElement(
|
return createElement(
|
||||||
Component,
|
Component,
|
||||||
{
|
{
|
||||||
...otherProps,
|
...finalProps,
|
||||||
...state.props,
|
id: finalProps.id ? finalProps.id : undefined,
|
||||||
key: widget.key,
|
key: widget.key,
|
||||||
ref: attachRef,
|
ref: attachRef,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
export const dataSourceCreator = () =>
|
|
||||||
({
|
|
||||||
dataSourceMap: {},
|
|
||||||
reloadDataSource: () => {},
|
|
||||||
}) as any;
|
|
||||||
@ -1,9 +1,8 @@
|
|||||||
import { invariant, isLowCodeComponentPackage, type Spec } from '@alilc/lowcode-shared';
|
import { invariant, isLowCodeComponentPackage, type Spec } from '@alilc/lowcode-shared';
|
||||||
import { forwardRef, useRef, useEffect } from 'react';
|
import { forwardRef, useRef, useEffect } from 'react';
|
||||||
import { isValidElementType } from 'react-is';
|
import { isValidElementType } from 'react-is';
|
||||||
import { useRenderContext } from '../app/context';
|
import { useRendererContext } from '../api/context';
|
||||||
import { reactiveStateFactory } from './reactiveState';
|
import { reactiveStateFactory } from './reactiveState';
|
||||||
import { dataSourceCreator } from './dataSource';
|
|
||||||
import { type ReactComponent, type ReactWidget, createElementByWidget } from './components';
|
import { type ReactComponent, type ReactWidget, createElementByWidget } from './components';
|
||||||
import { ModelContextProvider } from './context';
|
import { ModelContextProvider } from './context';
|
||||||
import { appendExternalStyle } from '../utils/element';
|
import { appendExternalStyle } from '../utils/element';
|
||||||
@ -39,9 +38,7 @@ export function getComponentByName(
|
|||||||
name: string,
|
name: string,
|
||||||
{ packageManager, boostsManager }: RenderContext,
|
{ packageManager, boostsManager }: RenderContext,
|
||||||
): ReactComponent {
|
): ReactComponent {
|
||||||
const componentsRecord = packageManager.getComponentsNameRecord<ReactComponent>();
|
const result = lowCodeComponentsCache.get(name) || packageManager.getComponent(name);
|
||||||
// read cache first
|
|
||||||
const result = lowCodeComponentsCache.get(name) || componentsRecord[name];
|
|
||||||
|
|
||||||
if (isLowCodeComponentPackage(result)) {
|
if (isLowCodeComponentPackage(result)) {
|
||||||
const { schema, ...metadata } = result;
|
const { schema, ...metadata } = result;
|
||||||
@ -87,8 +84,8 @@ export function createComponentBySchema(
|
|||||||
props: LowCodeComponentProps,
|
props: LowCodeComponentProps,
|
||||||
ref: ForwardedRef<any>,
|
ref: ForwardedRef<any>,
|
||||||
) {
|
) {
|
||||||
const renderContext = useRenderContext();
|
const renderContext = useRendererContext();
|
||||||
const { componentTreeModel } = renderContext;
|
const { options, componentTreeModel } = renderContext;
|
||||||
|
|
||||||
const modelRef = useRef<IComponentTreeModel<ReactComponent, ReactInstance>>();
|
const modelRef = useRef<IComponentTreeModel<ReactComponent, ReactInstance>>();
|
||||||
|
|
||||||
@ -110,7 +107,7 @@ export function createComponentBySchema(
|
|||||||
model.initialize({
|
model.initialize({
|
||||||
defaultProps: props,
|
defaultProps: props,
|
||||||
stateCreator: reactiveStateFactory,
|
stateCreator: reactiveStateFactory,
|
||||||
dataSourceCreator,
|
dataSourceCreator: options.dataSourceCreator,
|
||||||
});
|
});
|
||||||
|
|
||||||
model.triggerLifeCycle('constructor');
|
model.triggerLifeCycle('constructor');
|
||||||
@ -123,11 +120,6 @@ export function createComponentBySchema(
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const scopeValue = model.codeScope.value;
|
|
||||||
|
|
||||||
// init dataSource
|
|
||||||
scopeValue.reloadDataSource?.();
|
|
||||||
|
|
||||||
// trigger lifeCycles
|
// trigger lifeCycles
|
||||||
// componentDidMount?.();
|
// componentDidMount?.();
|
||||||
model.triggerLifeCycle('componentDidMount');
|
model.triggerLifeCycle('componentDidMount');
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
export const addLeadingSlash = (path: string): string => {
|
|
||||||
return path.charAt(0) === '/' ? path : `/${path}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface ExternalElementOptions {
|
export interface ExternalElementOptions {
|
||||||
id?: string;
|
id?: string;
|
||||||
root?: HTMLElement;
|
root?: HTMLElement;
|
||||||
|
|||||||
@ -14,10 +14,10 @@ describe('LifeCycleService', () => {
|
|||||||
lifeCycle.when(LifecyclePhase.Ready).finally(() => {
|
lifeCycle.when(LifecyclePhase.Ready).finally(() => {
|
||||||
result += '2';
|
result += '2';
|
||||||
});
|
});
|
||||||
lifeCycle.when(LifecyclePhase.AfterInitPackageLoad).then(() => {
|
lifeCycle.when(LifecyclePhase.Inited).then(() => {
|
||||||
result += '3';
|
result += '3';
|
||||||
});
|
});
|
||||||
lifeCycle.when(LifecyclePhase.AfterInitPackageLoad).finally(() => {
|
lifeCycle.when(LifecyclePhase.Inited).finally(() => {
|
||||||
result += '4';
|
result += '4';
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ describe('LifeCycleService', () => {
|
|||||||
|
|
||||||
expect(result).toEqual('12');
|
expect(result).toEqual('12');
|
||||||
|
|
||||||
lifeCycle.phase = LifecyclePhase.AfterInitPackageLoad;
|
lifeCycle.phase = LifecyclePhase.Inited;
|
||||||
|
|
||||||
await sleep();
|
await sleep();
|
||||||
|
|
||||||
|
|||||||
@ -30,21 +30,7 @@ export class RendererMain<RenderObject> {
|
|||||||
@IComponentTreeModelService private componentTreeModelService: IComponentTreeModelService,
|
@IComponentTreeModelService private componentTreeModelService: IComponentTreeModelService,
|
||||||
@IBoostsService private boostsService: IBoostsService,
|
@IBoostsService private boostsService: IBoostsService,
|
||||||
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
||||||
) {
|
) {}
|
||||||
this.lifeCycleService.when(LifecyclePhase.OptionsResolved).then(async () => {
|
|
||||||
const renderContext = {
|
|
||||||
schema: this.schemaService,
|
|
||||||
packageManager: this.packageManagementService,
|
|
||||||
boostsManager: this.boostsService,
|
|
||||||
componentTreeModel: this.componentTreeModelService,
|
|
||||||
lifeCycle: this.lifeCycleService,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.renderObject = await this.adapter(renderContext);
|
|
||||||
|
|
||||||
this.lifeCycleService.phase = LifecyclePhase.Ready;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async main(options: AppOptions, adapter: RenderAdapter<RenderObject>) {
|
async main(options: AppOptions, adapter: RenderAdapter<RenderObject>) {
|
||||||
const { schema, mode, plugins = [] } = options;
|
const { schema, mode, plugins = [] } = options;
|
||||||
@ -58,20 +44,26 @@ export class RendererMain<RenderObject> {
|
|||||||
|
|
||||||
this.codeRuntimeService.initialize(options.codeRuntime ?? {});
|
this.codeRuntimeService.initialize(options.codeRuntime ?? {});
|
||||||
|
|
||||||
this.lifeCycleService.phase = LifecyclePhase.OptionsResolved;
|
await this.lifeCycleService.setPhase(LifecyclePhase.OptionsResolved);
|
||||||
|
|
||||||
await this.lifeCycleService.when(LifecyclePhase.Ready);
|
const renderContext = {
|
||||||
|
schema: this.schemaService,
|
||||||
|
packageManager: this.packageManagementService,
|
||||||
|
boostsManager: this.boostsService,
|
||||||
|
componentTreeModel: this.componentTreeModelService,
|
||||||
|
lifeCycle: this.lifeCycleService,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.renderObject = await this.adapter(renderContext);
|
||||||
|
|
||||||
await this.extensionHostService.registerPlugin(plugins);
|
await this.extensionHostService.registerPlugin(plugins);
|
||||||
|
// 先加载插件提供 package loader
|
||||||
await this.packageManagementService.loadPackages(this.initOptions.packages ?? []);
|
await this.packageManagementService.loadPackages(this.initOptions.packages ?? []);
|
||||||
|
|
||||||
this.lifeCycleService.phase = LifecyclePhase.AfterInitPackageLoad;
|
await this.lifeCycleService.setPhase(LifecyclePhase.Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getApp(): Promise<RendererApplication<RenderObject>> {
|
getApp(): RendererApplication<RenderObject> {
|
||||||
await this.lifeCycleService.when(LifecyclePhase.AfterInitPackageLoad);
|
|
||||||
|
|
||||||
// construct application
|
// construct application
|
||||||
return Object.freeze<RendererApplication<RenderObject>>({
|
return Object.freeze<RendererApplication<RenderObject>>({
|
||||||
// develop use
|
// develop use
|
||||||
@ -85,6 +77,9 @@ export class RendererMain<RenderObject> {
|
|||||||
use: (plugin) => {
|
use: (plugin) => {
|
||||||
return this.extensionHostService.registerPlugin(plugin);
|
return this.extensionHostService.registerPlugin(plugin);
|
||||||
},
|
},
|
||||||
|
destroy: async () => {
|
||||||
|
return this.lifeCycleService.setPhase(LifecyclePhase.Destroying);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,11 +58,7 @@ export class CodeRuntimeService implements ICodeRuntimeService {
|
|||||||
if (!code) return undefined;
|
if (!code) return undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let result = this.evalCodeFunction(code, scope.value);
|
const result = this.evalCodeFunction(code, scope.value);
|
||||||
|
|
||||||
if (typeof result === 'function') {
|
|
||||||
result = result.bind(scope.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result as R;
|
return result as R;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -105,7 +101,8 @@ export class CodeRuntimeService implements ICodeRuntimeService {
|
|||||||
node: Spec.JSExpression | Spec.JSFunction,
|
node: Spec.JSExpression | Spec.JSFunction,
|
||||||
options: ResolveOptions,
|
options: ResolveOptions,
|
||||||
) {
|
) {
|
||||||
const v = this.run(node.value, options.scope || this.codeScope);
|
const scope = options.scope || this.codeScope;
|
||||||
|
const v = this.run(node.value, scope) as any;
|
||||||
|
|
||||||
if (typeof v === 'undefined' && node.mock) {
|
if (typeof v === 'undefined' && node.mock) {
|
||||||
return this.resolve(node.mock, options);
|
return this.resolve(node.mock, options);
|
||||||
|
|||||||
@ -63,7 +63,7 @@ export class CodeScope implements ICodeScope {
|
|||||||
private createProxy(): PlainObject {
|
private createProxy(): PlainObject {
|
||||||
return new Proxy(Object.create(null) as PlainObject, {
|
return new Proxy(Object.create(null) as PlainObject, {
|
||||||
set: (target, p, newValue) => {
|
set: (target, p, newValue) => {
|
||||||
this.set(p as string, newValue, true);
|
this.set(p as string, newValue);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
get: (_, p) => this.findValue(p) ?? undefined,
|
get: (_, p) => this.findValue(p) ?? undefined,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { type Plugin, type PluginContext } from './plugin';
|
|||||||
import { IBoostsService } from './boosts';
|
import { IBoostsService } from './boosts';
|
||||||
import { IPackageManagementService } from '../package';
|
import { IPackageManagementService } from '../package';
|
||||||
import { ISchemaService } from '../schema';
|
import { ISchemaService } from '../schema';
|
||||||
import { ILifeCycleService, LifecyclePhase } from '../lifeCycleService';
|
import { ILifeCycleService } from '../lifeCycleService';
|
||||||
|
|
||||||
interface IPluginRuntime extends Plugin {
|
interface IPluginRuntime extends Plugin {
|
||||||
status: 'setup' | 'ready';
|
status: 'setup' | 'ready';
|
||||||
@ -42,8 +42,8 @@ export class ExtensionHostService implements IExtensionHostService {
|
|||||||
schema: this.schemaService,
|
schema: this.schemaService,
|
||||||
packageManager: this.packageManagementService,
|
packageManager: this.packageManagementService,
|
||||||
|
|
||||||
whenLifeCylePhaseChange: (phase) => {
|
whenLifeCylePhaseChange: (phase, listener) => {
|
||||||
return this.lifeCycleService.when(phase);
|
return this.lifeCycleService.when(phase, listener);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { type EventEmitter, type IStore, type PlainObject } from '@alilc/lowcode-shared';
|
import { type EventEmitter, type IStore, type PlainObject } from '@alilc/lowcode-shared';
|
||||||
import { type IBoosts } from './boosts';
|
import { type IBoosts } from './boosts';
|
||||||
import { LifecyclePhase } from '../lifeCycleService';
|
import { ILifeCycleService } from '../lifeCycleService';
|
||||||
import { type ISchemaService } from '../schema';
|
import { type ISchemaService } from '../schema';
|
||||||
import { type IPackageManagementService } from '../package';
|
import { type IPackageManagementService } from '../package';
|
||||||
|
|
||||||
@ -8,12 +8,12 @@ export interface PluginContext<BoostsExtends = object> {
|
|||||||
eventEmitter: EventEmitter;
|
eventEmitter: EventEmitter;
|
||||||
globalState: IStore<PlainObject, string>;
|
globalState: IStore<PlainObject, string>;
|
||||||
boosts: IBoosts<BoostsExtends>;
|
boosts: IBoosts<BoostsExtends>;
|
||||||
schema: ISchemaService;
|
schema: Pick<ISchemaService, 'get' | 'set'>;
|
||||||
packageManager: IPackageManagementService;
|
packageManager: IPackageManagementService;
|
||||||
/**
|
/**
|
||||||
* 生命周期变更事件
|
* 生命周期变更事件
|
||||||
*/
|
*/
|
||||||
whenLifeCylePhaseChange(phase: LifecyclePhase): Promise<void>;
|
whenLifeCylePhaseChange: ILifeCycleService['when'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Plugin<BoostsExtends = object> {
|
export interface Plugin<BoostsExtends = object> {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Provide, createDecorator, Barrier } from '@alilc/lowcode-shared';
|
import { Provide, createDecorator, EventEmitter, EventDisposable } from '@alilc/lowcode-shared';
|
||||||
|
|
||||||
export const enum LifecyclePhase {
|
export const enum LifecyclePhase {
|
||||||
Starting = 1,
|
Starting = 1,
|
||||||
@ -7,7 +7,7 @@ export const enum LifecyclePhase {
|
|||||||
|
|
||||||
Ready = 3,
|
Ready = 3,
|
||||||
|
|
||||||
AfterInitPackageLoad = 4,
|
Destroying = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILifeCycleService {
|
export interface ILifeCycleService {
|
||||||
@ -16,18 +16,20 @@ export interface ILifeCycleService {
|
|||||||
*/
|
*/
|
||||||
phase: LifecyclePhase;
|
phase: LifecyclePhase;
|
||||||
|
|
||||||
|
setPhase(phase: LifecyclePhase): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise that resolves when a certain lifecycle phase
|
* Returns a promise that resolves when a certain lifecycle phase
|
||||||
* has started.
|
* has started.
|
||||||
*/
|
*/
|
||||||
when(phase: LifecyclePhase): Promise<void>;
|
when(phase: LifecyclePhase, listener: () => void | Promise<void>): EventDisposable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ILifeCycleService = createDecorator<ILifeCycleService>('lifeCycleService');
|
export const ILifeCycleService = createDecorator<ILifeCycleService>('lifeCycleService');
|
||||||
|
|
||||||
@Provide(ILifeCycleService)
|
@Provide(ILifeCycleService)
|
||||||
export class LifeCycleService implements ILifeCycleService {
|
export class LifeCycleService implements ILifeCycleService {
|
||||||
private readonly phaseWhen = new Map<LifecyclePhase, Barrier>();
|
private readonly phaseWhen = new EventEmitter();
|
||||||
|
|
||||||
private _phase = LifecyclePhase.Starting;
|
private _phase = LifecyclePhase.Starting;
|
||||||
|
|
||||||
@ -35,7 +37,7 @@ export class LifeCycleService implements ILifeCycleService {
|
|||||||
return this._phase;
|
return this._phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
set phase(value: LifecyclePhase) {
|
async setPhase(value: LifecyclePhase) {
|
||||||
if (value < this._phase) {
|
if (value < this._phase) {
|
||||||
throw new Error('Lifecycle cannot go backwards');
|
throw new Error('Lifecycle cannot go backwards');
|
||||||
}
|
}
|
||||||
@ -44,28 +46,27 @@ export class LifeCycleService implements ILifeCycleService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.logService.trace(`lifecycle: phase changed (value: ${value})`);
|
|
||||||
|
|
||||||
this._phase = value;
|
this._phase = value;
|
||||||
|
|
||||||
const barrier = this.phaseWhen.get(this._phase);
|
await this.phaseWhen.emit(LifecyclePhaseToString(value));
|
||||||
if (barrier) {
|
|
||||||
barrier.open();
|
|
||||||
this.phaseWhen.delete(this._phase);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async when(phase: LifecyclePhase): Promise<void> {
|
when(phase: LifecyclePhase, listener: () => void | Promise<void>) {
|
||||||
if (phase <= this._phase) {
|
return this.phaseWhen.on(LifecyclePhaseToString(phase), listener);
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let barrier = this.phaseWhen.get(phase);
|
export function LifecyclePhaseToString(phase: LifecyclePhase): string {
|
||||||
if (!barrier) {
|
switch (phase) {
|
||||||
barrier = new Barrier();
|
case LifecyclePhase.Starting:
|
||||||
this.phaseWhen.set(phase, barrier);
|
return 'Starting';
|
||||||
}
|
case LifecyclePhase.OptionsResolved:
|
||||||
|
return 'OptionsResolved';
|
||||||
await barrier.wait();
|
case LifecyclePhase.Ready:
|
||||||
|
return 'Ready';
|
||||||
|
case LifecyclePhase.Inited:
|
||||||
|
return 'Inited';
|
||||||
|
case LifecyclePhase.Destroying:
|
||||||
|
return 'Destroying';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,9 +15,8 @@ export interface NormalizedComponentNode extends Spec.ComponentNode {
|
|||||||
|
|
||||||
export interface InitializeModelOptions {
|
export interface InitializeModelOptions {
|
||||||
defaultProps?: PlainObject | undefined;
|
defaultProps?: PlainObject | undefined;
|
||||||
|
|
||||||
stateCreator: ModelScopeStateCreator;
|
stateCreator: ModelScopeStateCreator;
|
||||||
dataSourceCreator: ModelScopeDataSourceCreator;
|
dataSourceCreator?: ModelScopeDataSourceCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,14 +59,6 @@ export interface IComponentTreeModel<Component, ComponentInstance = unknown> {
|
|||||||
export type ModelScopeStateCreator = (initalState: PlainObject) => Spec.InstanceStateApi;
|
export type ModelScopeStateCreator = (initalState: PlainObject) => Spec.InstanceStateApi;
|
||||||
export type ModelScopeDataSourceCreator = (...args: any[]) => Spec.InstanceDataSourceApi;
|
export type ModelScopeDataSourceCreator = (...args: any[]) => Spec.InstanceDataSourceApi;
|
||||||
|
|
||||||
const defaultDataSourceSchema: Spec.ComponentDataSource = {
|
|
||||||
list: [],
|
|
||||||
dataHandler: {
|
|
||||||
type: 'JSFunction',
|
|
||||||
value: '() => {}',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface ComponentTreeModelOptions {
|
export interface ComponentTreeModelOptions {
|
||||||
id?: string;
|
id?: string;
|
||||||
metadata?: PlainObject;
|
metadata?: PlainObject;
|
||||||
@ -108,7 +99,7 @@ export class ComponentTreeModel<Component, ComponentInstance = unknown>
|
|||||||
state = {},
|
state = {},
|
||||||
defaultProps: defaultSchemaProps,
|
defaultProps: defaultSchemaProps,
|
||||||
props = {},
|
props = {},
|
||||||
dataSource = defaultDataSourceSchema,
|
dataSource,
|
||||||
methods = {},
|
methods = {},
|
||||||
} = this.componentsTree;
|
} = this.componentsTree;
|
||||||
|
|
||||||
@ -120,16 +111,22 @@ export class ComponentTreeModel<Component, ComponentInstance = unknown>
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const initalState = this.codeRuntime.resolve(state, { scope: this.codeScope });
|
|
||||||
const initalProps = this.codeRuntime.resolve(props, { scope: this.codeScope });
|
const initalProps = this.codeRuntime.resolve(props, { scope: this.codeScope });
|
||||||
|
this.codeScope.setValue({ props: { ...defaultProps, ...initalProps } });
|
||||||
|
|
||||||
|
const initalState = this.codeRuntime.resolve(state, { scope: this.codeScope });
|
||||||
const stateApi = stateCreator(initalState);
|
const stateApi = stateCreator(initalState);
|
||||||
const dataSourceApi = dataSourceCreator(dataSource, stateApi);
|
this.codeScope.setValue(stateApi);
|
||||||
|
|
||||||
|
let dataSourceApi: Spec.InstanceDataSourceApi | undefined;
|
||||||
|
if (dataSource && dataSourceCreator) {
|
||||||
|
const dataSourceProps = this.codeRuntime.resolve(dataSource, { scope: this.codeScope });
|
||||||
|
dataSourceApi = dataSourceCreator(dataSourceProps, stateApi);
|
||||||
|
}
|
||||||
|
|
||||||
this.codeScope.setValue(
|
this.codeScope.setValue(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{
|
{
|
||||||
props: { ...defaultProps, ...initalProps },
|
|
||||||
$: (ref: string) => {
|
$: (ref: string) => {
|
||||||
const insArr = this.instanceMap.get(ref);
|
const insArr = this.instanceMap.get(ref);
|
||||||
if (!insArr) return undefined;
|
if (!insArr) return undefined;
|
||||||
@ -139,7 +136,6 @@ export class ComponentTreeModel<Component, ComponentInstance = unknown>
|
|||||||
return this.instanceMap.get(ref) ?? [];
|
return this.instanceMap.get(ref) ?? [];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
stateApi,
|
|
||||||
dataSourceApi,
|
dataSourceApi,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
import { get as lodashGet } from 'lodash-es';
|
import { get as lodashGet } from 'lodash-es';
|
||||||
import { PackageLoader } from './loader';
|
import { PackageLoader } from './loader';
|
||||||
import { ISchemaService } from '../schema';
|
import { ISchemaService } from '../schema';
|
||||||
import { ILifeCycleService, LifecyclePhase } from '../lifeCycleService';
|
import { ILifeCycleService } from '../lifeCycleService';
|
||||||
|
|
||||||
export interface NormalizedPackage {
|
export interface NormalizedPackage {
|
||||||
id: string;
|
id: string;
|
||||||
@ -33,16 +33,13 @@ export interface IPackageManagementService {
|
|||||||
|
|
||||||
setLibraryByPackageName(packageName: string, library: any): void;
|
setLibraryByPackageName(packageName: string, library: any): void;
|
||||||
|
|
||||||
getLibraryByComponentMap(componentMap: Spec.ComponentMap): any;
|
getLibraryByComponentMap(
|
||||||
|
componentMap: Spec.ComponentMap,
|
||||||
|
): { key: string; value: any } | undefined;
|
||||||
|
|
||||||
/** 解析组件映射 */
|
/** 解析组件映射 */
|
||||||
resolveComponentMaps(componentMaps: Spec.ComponentMap[]): void;
|
resolveComponentMaps(componentMaps: Spec.ComponentMap[]): void;
|
||||||
|
|
||||||
/** 获取组件映射对象,key = componentName value = component */
|
|
||||||
getComponentsNameRecord<C = unknown>(
|
|
||||||
componentMaps?: Spec.ComponentMap[],
|
|
||||||
): Record<string, C | LowCodeComponent>;
|
|
||||||
|
|
||||||
/** 通过组件名获取对应的组件 */
|
/** 通过组件名获取对应的组件 */
|
||||||
getComponent<C = unknown>(componentName: string): C | LowCodeComponent | undefined;
|
getComponent<C = unknown>(componentName: string): C | LowCodeComponent | undefined;
|
||||||
/** 注册组件 */
|
/** 注册组件 */
|
||||||
@ -72,8 +69,7 @@ export class PackageManagementService implements IPackageManagementService {
|
|||||||
@ISchemaService private schemaService: ISchemaService,
|
@ISchemaService private schemaService: ISchemaService,
|
||||||
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
||||||
) {
|
) {
|
||||||
this.lifeCycleService.when(LifecyclePhase.AfterInitPackageLoad).then(() => {
|
this.schemaService.onChange('componentsMap', (componentsMaps) => {
|
||||||
const componentsMaps = this.schemaService.get('componentsMap');
|
|
||||||
this.resolveComponentMaps(componentsMaps);
|
this.resolveComponentMaps(componentsMaps);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -109,19 +105,23 @@ export class PackageManagementService implements IPackageManagementService {
|
|||||||
this.packageStore.set(packageName, library);
|
this.packageStore.set(packageName, library);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLibraryByComponentMap(componentMap: Spec.ComponentMap) {
|
getLibraryByComponentMap(
|
||||||
if (this.packageStore.has(componentMap.package!)) {
|
componentMap: Spec.ComponentMap,
|
||||||
|
): { key: string; value: any } | undefined {
|
||||||
|
if (!componentMap.componentName && !componentMap.exportName) return;
|
||||||
|
|
||||||
|
if (this.packageStore.has(componentMap.package)) {
|
||||||
const library = this.packageStore.get(componentMap.package!);
|
const library = this.packageStore.get(componentMap.package!);
|
||||||
// export { exportName } from xxx exportName === global.libraryName.exportName
|
// export { exportName } from xxx exportName === global.libraryName.exportName
|
||||||
// export exportName from xxx exportName === global.libraryName.default || global.libraryName
|
// 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 componentName = exportName.subName, if exportName empty subName donot use
|
||||||
const paths =
|
const paths =
|
||||||
componentMap.exportName && componentMap.subName ? componentMap.subName.split('.') : [];
|
componentMap.exportName && componentMap.subName ? componentMap.subName.split('.') : [];
|
||||||
|
|
||||||
|
// if exportName === nil, exportName === componentName;
|
||||||
const exportName = componentMap.exportName ?? componentMap.componentName;
|
const exportName = componentMap.exportName ?? componentMap.componentName;
|
||||||
|
|
||||||
if (componentMap.destructuring) {
|
if (exportName && componentMap.destructuring) {
|
||||||
paths.unshift(exportName);
|
paths.unshift(exportName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,10 +130,12 @@ export class PackageManagementService implements IPackageManagementService {
|
|||||||
result = result[path] || result;
|
result = result[path] || result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
// export { exportName as componentName } from package
|
||||||
|
return {
|
||||||
|
key: componentMap.componentName ?? componentMap.exportName!,
|
||||||
|
value: result,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveComponentMaps(componentMaps: Spec.ComponentMap[]) {
|
resolveComponentMaps(componentMaps: Spec.ComponentMap[]) {
|
||||||
@ -146,22 +148,15 @@ export class PackageManagementService implements IPackageManagementService {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const result = this.getLibraryByComponentMap(map);
|
const result = this.getLibraryByComponentMap(map);
|
||||||
if (map.componentName && result) this.componentsRecord[map.componentName] = result;
|
if (result) {
|
||||||
|
this.componentsRecord[result.key] = result.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getComponentsNameRecord(componentMaps?: Spec.ComponentMap[]) {
|
|
||||||
if (componentMaps) {
|
|
||||||
const newMaps = componentMaps.filter((item) => !this.componentsRecord[item.componentName]);
|
|
||||||
this.resolveComponentMaps(newMaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...this.componentsRecord };
|
|
||||||
}
|
|
||||||
|
|
||||||
getComponent(componentName: string) {
|
getComponent(componentName: string) {
|
||||||
return this.componentsRecord[componentName];
|
return lodashGet(this.componentsRecord, componentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerComponentByName(componentName: string, Component: unknown) {
|
registerComponentByName(componentName: string, Component: unknown) {
|
||||||
|
|||||||
@ -42,7 +42,9 @@ export class RuntimeIntlService implements IRuntimeIntlService {
|
|||||||
@ICodeRuntimeService private codeRuntimeService: ICodeRuntimeService,
|
@ICodeRuntimeService private codeRuntimeService: ICodeRuntimeService,
|
||||||
@ISchemaService private schemaService: ISchemaService,
|
@ISchemaService private schemaService: ISchemaService,
|
||||||
) {
|
) {
|
||||||
this.lifeCycleService.when(LifecyclePhase.OptionsResolved).then(() => {
|
this.injectScope();
|
||||||
|
|
||||||
|
this.lifeCycleService.when(LifecyclePhase.OptionsResolved, () => {
|
||||||
const config = this.schemaService.get('config');
|
const config = this.schemaService.get('config');
|
||||||
const i18nTranslations = this.schemaService.get('i18n');
|
const i18nTranslations = this.schemaService.get('i18n');
|
||||||
|
|
||||||
@ -55,10 +57,6 @@ export class RuntimeIntlService implements IRuntimeIntlService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.lifeCycleService.when(LifecyclePhase.Ready).then(() => {
|
|
||||||
this.toExpose();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t(descriptor: MessageDescriptor): string {
|
t(descriptor: MessageDescriptor): string {
|
||||||
@ -85,7 +83,7 @@ export class RuntimeIntlService implements IRuntimeIntlService {
|
|||||||
this.intl.addTranslations(locale, translations);
|
this.intl.addTranslations(locale, translations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private toExpose(): void {
|
private injectScope(): void {
|
||||||
const exposed: Spec.IntlApi = {
|
const exposed: Spec.IntlApi = {
|
||||||
i18n: (key, params) => {
|
i18n: (key, params) => {
|
||||||
return this.t({ key, params });
|
return this.t({ key, params });
|
||||||
|
|||||||
@ -8,12 +8,11 @@ import {
|
|||||||
import { isPlainObject } from 'lodash-es';
|
import { isPlainObject } from 'lodash-es';
|
||||||
import { IPackageManagementService } from './package';
|
import { IPackageManagementService } from './package';
|
||||||
import { ICodeRuntimeService } from './code-runtime';
|
import { ICodeRuntimeService } from './code-runtime';
|
||||||
import { ILifeCycleService, LifecyclePhase } from './lifeCycleService';
|
|
||||||
import { ISchemaService } from './schema';
|
import { ISchemaService } from './schema';
|
||||||
|
|
||||||
export interface IRuntimeUtilService {
|
export interface IRuntimeUtilService {
|
||||||
add(utilItem: Spec.Util): void;
|
add(utilItem: Spec.Util, force?: boolean): void;
|
||||||
add(name: string, target: AnyFunction | PlainObject): void;
|
add(name: string, target: AnyFunction | PlainObject, force?: boolean): void;
|
||||||
|
|
||||||
remove(name: string): void;
|
remove(name: string): void;
|
||||||
}
|
}
|
||||||
@ -27,38 +26,61 @@ export class RuntimeUtilService implements IRuntimeUtilService {
|
|||||||
constructor(
|
constructor(
|
||||||
@ICodeRuntimeService private codeRuntimeService: ICodeRuntimeService,
|
@ICodeRuntimeService private codeRuntimeService: ICodeRuntimeService,
|
||||||
@IPackageManagementService private packageManagementService: IPackageManagementService,
|
@IPackageManagementService private packageManagementService: IPackageManagementService,
|
||||||
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
|
||||||
@ISchemaService private schemaService: ISchemaService,
|
@ISchemaService private schemaService: ISchemaService,
|
||||||
) {
|
) {
|
||||||
this.lifeCycleService.when(LifecyclePhase.AfterInitPackageLoad).then(() => {
|
this.injectScope();
|
||||||
const utils = this.schemaService.get('utils') ?? [];
|
|
||||||
|
this.schemaService.onChange('utils', (utils = []) => {
|
||||||
for (const util of utils) {
|
for (const util of utils) {
|
||||||
this.add(util);
|
this.add(util);
|
||||||
}
|
}
|
||||||
this.toExpose();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
add(utilItem: Spec.Util): void;
|
add(utilItem: Spec.Util, force?: boolean): void;
|
||||||
add(name: string, fn: AnyFunction | PlainObject): void;
|
add(name: string, fn: AnyFunction | PlainObject, force?: boolean): void;
|
||||||
add(name: Spec.Util | string, fn?: AnyFunction | PlainObject): void {
|
add(util: Spec.Util | string, fn?: AnyFunction | PlainObject | boolean, force?: boolean): void {
|
||||||
if (typeof name === 'string') {
|
let name: string;
|
||||||
if (fn) {
|
let utilObj: AnyFunction | PlainObject | Spec.Util;
|
||||||
if (isPlainObject(fn)) {
|
|
||||||
if ((fn as PlainObject).destructuring) {
|
if (typeof util === 'string') {
|
||||||
for (const key of Object.keys(fn)) {
|
if (!fn) return;
|
||||||
this.add(key, (fn as PlainObject)[key]);
|
|
||||||
}
|
name = util;
|
||||||
} else {
|
utilObj = fn as AnyFunction | PlainObject;
|
||||||
this.utilsMap.set(name, fn);
|
|
||||||
}
|
|
||||||
} else if (typeof fn === 'function') {
|
|
||||||
this.utilsMap.set(name, fn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const util = this.parseUtil(name);
|
if (!util) return;
|
||||||
if (util) this.add(name.name, util);
|
|
||||||
|
name = util.name;
|
||||||
|
utilObj = util;
|
||||||
|
force = fn as boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addUtilByName(name, utilObj, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
private addUtilByName(
|
||||||
|
name: string,
|
||||||
|
fn: AnyFunction | PlainObject | Spec.Util,
|
||||||
|
force?: boolean,
|
||||||
|
): void {
|
||||||
|
if (this.utilsMap.has(name) && !force) return;
|
||||||
|
|
||||||
|
if (isPlainObject(fn)) {
|
||||||
|
if ((fn as Spec.Util).type === 'function' || (fn as Spec.Util).type === 'npm') {
|
||||||
|
const utilFn = this.parseUtil(fn as Spec.Util);
|
||||||
|
if (utilFn) {
|
||||||
|
this.addUtilByName(utilFn.key, utilFn.value, force);
|
||||||
|
}
|
||||||
|
} else if ((fn as PlainObject).destructuring) {
|
||||||
|
for (const key of Object.keys(fn)) {
|
||||||
|
this.addUtilByName(key, (fn as PlainObject)[key], force);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.utilsMap.set(name, fn);
|
||||||
|
}
|
||||||
|
} else if (typeof fn === 'function') {
|
||||||
|
this.utilsMap.set(name, fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,13 +91,16 @@ export class RuntimeUtilService implements IRuntimeUtilService {
|
|||||||
private parseUtil(utilItem: Spec.Util) {
|
private parseUtil(utilItem: Spec.Util) {
|
||||||
if (utilItem.type === 'function') {
|
if (utilItem.type === 'function') {
|
||||||
const { content } = utilItem;
|
const { content } = utilItem;
|
||||||
return this.codeRuntimeService.run(content.value);
|
return {
|
||||||
|
key: utilItem.name,
|
||||||
|
value: this.codeRuntimeService.run(content.value),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return this.packageManagementService.getLibraryByComponentMap(utilItem.content);
|
return this.packageManagementService.getLibraryByComponentMap(utilItem.content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private toExpose(): void {
|
private injectScope(): void {
|
||||||
const exposed = new Proxy(Object.create(null), {
|
const exposed = new Proxy(Object.create(null), {
|
||||||
get: (_, p: string) => {
|
get: (_, p: string) => {
|
||||||
return this.utilsMap.get(p);
|
return this.utilsMap.get(p);
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import {
|
|||||||
Provide,
|
Provide,
|
||||||
type IStore,
|
type IStore,
|
||||||
KeyValueStore,
|
KeyValueStore,
|
||||||
|
EventEmitter,
|
||||||
|
type EventDisposable,
|
||||||
} from '@alilc/lowcode-shared';
|
} from '@alilc/lowcode-shared';
|
||||||
import { isObject } from 'lodash-es';
|
import { isObject } from 'lodash-es';
|
||||||
import { schemaValidation } from './validation';
|
import { schemaValidation } from './validation';
|
||||||
@ -19,7 +21,12 @@ export interface ISchemaService {
|
|||||||
|
|
||||||
get<K extends NormalizedSchemaKey>(key: K): NormalizedSchema[K];
|
get<K extends NormalizedSchemaKey>(key: K): NormalizedSchema[K];
|
||||||
|
|
||||||
set<K extends NormalizedSchemaKey>(key: K, value: NormalizedSchema[K]): void;
|
set<K extends NormalizedSchemaKey>(key: K, value: NormalizedSchema[K]): Promise<void>;
|
||||||
|
|
||||||
|
onChange<K extends NormalizedSchemaKey>(
|
||||||
|
key: K,
|
||||||
|
listener: (v: NormalizedSchema[K]) => void,
|
||||||
|
): EventDisposable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ISchemaService = createDecorator<ISchemaService>('schemaService');
|
export const ISchemaService = createDecorator<ISchemaService>('schemaService');
|
||||||
@ -33,13 +40,18 @@ export class SchemaService implements ISchemaService {
|
|||||||
setterValidation: schemaValidation,
|
setterValidation: schemaValidation,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private notifyEmiiter = new EventEmitter();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
||||||
@ICodeRuntimeService private codeRuntimeService: ICodeRuntimeService,
|
@ICodeRuntimeService private codeRuntimeService: ICodeRuntimeService,
|
||||||
) {
|
) {
|
||||||
this.lifeCycleService.when(LifecyclePhase.Ready).then(() => {
|
this.onChange('constants', (value = {}) => {
|
||||||
const constants = this.get('constants') ?? {};
|
this.codeRuntimeService.getScope().set('constants', value);
|
||||||
this.codeRuntimeService.getScope().set('constants', constants);
|
});
|
||||||
|
|
||||||
|
this.lifeCycleService.when(LifecyclePhase.Destroying, () => {
|
||||||
|
this.notifyEmiiter.removeAll();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,11 +66,21 @@ export class SchemaService implements ISchemaService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
set<K extends NormalizedSchemaKey>(key: K, value: NormalizedSchema[K]): void {
|
async set<K extends NormalizedSchemaKey>(key: K, value: NormalizedSchema[K]): Promise<void> {
|
||||||
this.store.set(key, value);
|
if (value !== this.get(key)) {
|
||||||
|
this.store.set(key, value);
|
||||||
|
await this.notifyEmiiter.emit(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get<K extends NormalizedSchemaKey>(key: K): NormalizedSchema[K] {
|
get<K extends NormalizedSchemaKey>(key: K): NormalizedSchema[K] {
|
||||||
return this.store.get(key) as NormalizedSchema[K];
|
return this.store.get(key) as NormalizedSchema[K];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChange<K extends keyof NormalizedSchema>(
|
||||||
|
key: K,
|
||||||
|
listener: (v: NormalizedSchema[K]) => void | Promise<void>,
|
||||||
|
): EventDisposable {
|
||||||
|
return this.notifyEmiiter.on(key, listener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,21 +3,24 @@ import { type Plugin } from './services/extension';
|
|||||||
import { type ISchemaService } from './services/schema';
|
import { type ISchemaService } from './services/schema';
|
||||||
import { type IPackageManagementService } from './services/package';
|
import { type IPackageManagementService } from './services/package';
|
||||||
import { type CodeRuntimeInitializeOptions } from './services/code-runtime';
|
import { type CodeRuntimeInitializeOptions } from './services/code-runtime';
|
||||||
|
import { type ModelScopeDataSourceCreator } from './services/model';
|
||||||
|
|
||||||
export interface AppOptions {
|
export interface AppOptions {
|
||||||
schema: Spec.Project;
|
schema: Spec.Project;
|
||||||
packages?: Spec.Package[];
|
packages?: Spec.Package[];
|
||||||
plugins?: Plugin[];
|
plugins?: Plugin[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 运行模式
|
* 运行模式
|
||||||
*/
|
*/
|
||||||
mode?: 'development' | 'production';
|
mode?: 'development' | 'production';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* code runtime 设置选项
|
* code runtime 设置选项
|
||||||
*/
|
*/
|
||||||
codeRuntime?: CodeRuntimeInitializeOptions;
|
codeRuntime?: CodeRuntimeInitializeOptions;
|
||||||
|
/**
|
||||||
|
* 数据源创建工厂函数
|
||||||
|
*/
|
||||||
|
dataSourceCreator?: ModelScopeDataSourceCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RendererApplication<Render = unknown> = {
|
export type RendererApplication<Render = unknown> = {
|
||||||
@ -28,4 +31,6 @@ export type RendererApplication<Render = unknown> = {
|
|||||||
readonly packageManager: IPackageManagementService;
|
readonly packageManager: IPackageManagementService;
|
||||||
|
|
||||||
use(plugin: Plugin): Promise<void>;
|
use(plugin: Plugin): Promise<void>;
|
||||||
|
|
||||||
|
destroy(): Promise<void>;
|
||||||
} & Render;
|
} & Render;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
} from './history';
|
} from './history';
|
||||||
import { createRouterMatcher } from './matcher';
|
import { createRouterMatcher } from './matcher';
|
||||||
import { type PathParserOptions, type PathParams } from './utils/path-parser';
|
import { type PathParserOptions, type PathParams } from './utils/path-parser';
|
||||||
import { parseURL, stringifyURL } from './utils/url';
|
import { mergeSearchParams, parseURL, stringifyURL } from './utils/url';
|
||||||
import { isSameRouteLocation } from './utils/helper';
|
import { isSameRouteLocation } from './utils/helper';
|
||||||
import type {
|
import type {
|
||||||
RouteRecord,
|
RouteRecord,
|
||||||
@ -77,11 +77,11 @@ export function createRouter(options: RouterOptions): Router {
|
|||||||
|
|
||||||
function resolve(
|
function resolve(
|
||||||
rawLocation: RawRouteLocation,
|
rawLocation: RawRouteLocation,
|
||||||
currentLocation?: RouteLocationNormalized,
|
current?: RouteLocationNormalized,
|
||||||
): RouteLocationNormalized & {
|
): RouteLocationNormalized & {
|
||||||
href: string;
|
href: string;
|
||||||
} {
|
} {
|
||||||
currentLocation = Object.assign({}, currentLocation || currentLocation);
|
currentLocation = Object.assign({}, current || currentLocation);
|
||||||
|
|
||||||
if (typeof rawLocation === 'string') {
|
if (typeof rawLocation === 'string') {
|
||||||
const locationNormalized = parseURL(rawLocation);
|
const locationNormalized = parseURL(rawLocation);
|
||||||
@ -89,7 +89,10 @@ export function createRouter(options: RouterOptions): Router {
|
|||||||
const href = routerHistory.createHref(locationNormalized.fullPath);
|
const href = routerHistory.createHref(locationNormalized.fullPath);
|
||||||
|
|
||||||
return Object.assign(locationNormalized, matchedRoute, {
|
return Object.assign(locationNormalized, matchedRoute, {
|
||||||
searchParams: locationNormalized.searchParams,
|
searchParams: mergeSearchParams(
|
||||||
|
currentLocation.searchParams,
|
||||||
|
locationNormalized.searchParams,
|
||||||
|
),
|
||||||
hash: decodeURIComponent(locationNormalized.hash),
|
hash: decodeURIComponent(locationNormalized.hash),
|
||||||
redirectedFrom: undefined,
|
redirectedFrom: undefined,
|
||||||
href,
|
href,
|
||||||
|
|||||||
@ -45,3 +45,14 @@ export function stringifyURL(location: {
|
|||||||
const searchStr = location.searchParams ? location.searchParams.toString() : '';
|
const searchStr = location.searchParams ? location.searchParams.toString() : '';
|
||||||
return location.path + (searchStr && '?') + searchStr + (location.hash || '');
|
return location.path + (searchStr && '?') + searchStr + (location.hash || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mergeSearchParams(
|
||||||
|
a: URLSearchParams | undefined,
|
||||||
|
b: URLSearchParams | undefined,
|
||||||
|
): URLSearchParams {
|
||||||
|
if (!a && !b) return new URLSearchParams();
|
||||||
|
if (!a) return b!;
|
||||||
|
if (!b) return a;
|
||||||
|
|
||||||
|
return new URLSearchParams([...Array.from(a.entries()), ...Array.from(b.entries())]);
|
||||||
|
}
|
||||||
|
|||||||
@ -44,7 +44,7 @@ export interface Project {
|
|||||||
/**
|
/**
|
||||||
* 当前应用元数据信息
|
* 当前应用元数据信息
|
||||||
*/
|
*/
|
||||||
meta?: Record<string, JSONObject>;
|
meta?: Record<string, JSONValue | JSONObject>;
|
||||||
/**
|
/**
|
||||||
* 当前应用的公共数据源
|
* 当前应用的公共数据源
|
||||||
* @deprecated
|
* @deprecated
|
||||||
@ -92,13 +92,13 @@ export interface ProjectConfig {
|
|||||||
*/
|
*/
|
||||||
export interface ComponentMap {
|
export interface ComponentMap {
|
||||||
/**
|
/**
|
||||||
* 协议中的组件名,唯一性,对应包导出的组件名,是一个有效的 JS 标识符,而且是大写字母打头
|
* 协议中的组件名,对应包导出的组件名,是一个有效的 JS 标识符
|
||||||
*/
|
*/
|
||||||
componentName: string;
|
componentName?: string;
|
||||||
/**
|
/**
|
||||||
* npm 公域的 package name
|
* npm 公域的 package name,唯一性
|
||||||
*/
|
*/
|
||||||
package?: string;
|
package: string;
|
||||||
/**
|
/**
|
||||||
* package version
|
* package version
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user