Skip to content

Commit

Permalink
fix: lifeCycle events and router plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
1ncounter committed Jun 19, 2024
1 parent 37d07f1 commit 61bc8e6
Show file tree
Hide file tree
Showing 34 changed files with 197 additions and 114 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pnpm-lock.yaml
deploy-space/packages
deploy-space/.env


# IDE
.vscode
.idea
Expand Down
4 changes: 2 additions & 2 deletions packages/react-renderer/src/api/app.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createRenderer, type AppOptions } from '@alilc/lowcode-renderer-core';
import { type ComponentType } from 'react';
import { type Root, createRoot } from 'react-dom/client';
import { ApplicationView, RendererContext, extension } from '../app';
import { ApplicationView, RendererContext, boosts } from '../app';

export interface ReactAppOptions extends AppOptions {
faultComponent?: ComponentType<any>;
Expand All @@ -17,7 +17,7 @@ export const createApp = async (options: ReactAppOptions) => {
// }

// extends boosts
extension.install(boostsManager);
boostsManager.extend(boosts.toExpose());

let root: Root | undefined;

Expand Down
2 changes: 1 addition & 1 deletion packages/react-renderer/src/api/component.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createRenderer, type AppOptions } from '@alilc/lowcode-renderer-core';
import { FunctionComponent } from 'react';
import { type LowCodeComponentProps, createComponentBySchema } from '../runtime/component';
import { type LowCodeComponentProps, createComponentBySchema } from '../runtime/schema';
import { RendererContext } from '../app/context';

interface Render {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Plugin, type IBoostsService } from '@alilc/lowcode-renderer-core';
import { type Plugin } from '@alilc/lowcode-renderer-core';
import { type ComponentType, type PropsWithChildren } from 'react';

export type WrapperComponent = ComponentType<PropsWithChildren<any>>;
Expand All @@ -9,13 +9,13 @@ export interface OutletProps {

export type Outlet = ComponentType<OutletProps>;

export interface ReactRendererExtensionApi {
export interface ReactRendererBoostsApi {
addAppWrapper(appWrapper: WrapperComponent): void;

setOutlet(outlet: Outlet): void;
}

class ReactRendererExtension {
class ReactRendererBoosts {
private wrappers: WrapperComponent[] = [];

private outlet: Outlet | null = null;
Expand All @@ -28,7 +28,7 @@ class ReactRendererExtension {
return this.outlet;
}

toExpose(): ReactRendererExtensionApi {
toExpose(): ReactRendererBoostsApi {
return {
addAppWrapper: (appWrapper) => {
if (appWrapper) this.wrappers.push(appWrapper);
Expand All @@ -38,14 +38,10 @@ class ReactRendererExtension {
},
};
}

install(boostsService: IBoostsService) {
boostsService.extend(this.toExpose());
}
}

export const extension = new ReactRendererExtension();
export const boosts = new ReactRendererBoosts();

export function defineRendererPlugin(plugin: Plugin<ReactRendererExtensionApi>) {
export function defineRendererPlugin(plugin: Plugin<ReactRendererBoostsApi>) {
return plugin;
}
2 changes: 1 addition & 1 deletion packages/react-renderer/src/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './context';
export * from './extension';
export * from './boosts';
export * from './view';
8 changes: 4 additions & 4 deletions packages/react-renderer/src/app/view.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useRenderContext } from './context';
import { getComponentByName } from '../runtime/component';
import { extension } from './extension';
import { getComponentByName } from '../runtime/schema';
import { boosts } from './boosts';

export function ApplicationView() {
const renderContext = useRenderContext();
const { schema } = renderContext;
const appWrappers = extension.getAppWrappers();
const Outlet = extension.getOutlet();
const appWrappers = boosts.getAppWrappers();
const Outlet = boosts.getOutlet();

if (!Outlet) return null;

Expand Down
2 changes: 1 addition & 1 deletion packages/react-renderer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export * from './router';

export type { Spec, ProCodeComponent, LowCodeComponent } from '@alilc/lowcode-shared';
export type { PackageLoader, CodeScope, Plugin } from '@alilc/lowcode-renderer-core';
export type { RendererExtends } from './app/extension';
export type { ReactRendererBoostsApi } from './app/boosts';
1 change: 1 addition & 0 deletions packages/react-renderer/src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './context';
export * from './plugin';
export type * from '@alilc/lowcode-renderer-router';
5 changes: 3 additions & 2 deletions packages/react-renderer/src/router/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineRendererPlugin } from '../app/extension';
import { defineRendererPlugin } from '../app/boosts';
import { LifecyclePhase } from '@alilc/lowcode-renderer-core';
import { createRouter, type RouterOptions } from '@alilc/lowcode-renderer-router';
import { createRouterView } from './routerView';
Expand Down Expand Up @@ -29,13 +29,14 @@ export const routerPlugin = defineRendererPlugin({
const router = createRouter(routerConfig);

boosts.codeRuntime.getScope().set('router', router);
boosts.temporaryUse('router', router);

const RouterView = createRouterView(router);

boosts.addAppWrapper(RouterView);
boosts.setOutlet(RouteOutlet);

whenLifeCylePhaseChange(LifecyclePhase.Ready).then(() => {
whenLifeCylePhaseChange(LifecyclePhase.AfterInitPackageLoad).then(() => {
return router.isReady();
});
},
Expand Down
4 changes: 2 additions & 2 deletions packages/react-renderer/src/router/route.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useMemo } from 'react';
import { useRenderContext } from '../app/context';
import { OutletProps } from '../app/extension';
import { OutletProps } from '../app/boosts';
import { useRouteLocation } from './context';
import { createComponentBySchema } from '../runtime/component';
import { createComponentBySchema } from '../runtime/schema';

export function RouteOutlet(props: OutletProps) {
const context = useRenderContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { type ComponentType, type ReactInstance, useMemo, createElement } from '
import { useRenderContext } from '../app/context';
import { useReactiveStore } from './hooks/useReactiveStore';
import { useModel } from './context';
import { getComponentByName } from './component';
import { getComponentByName } from './schema';

export type ReactComponent = ComponentType<any>;
export type ReactWidget = IWidget<ReactComponent, ReactInstance>;
Expand Down
2 changes: 1 addition & 1 deletion packages/react-renderer/src/runtime/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IComponentTreeModel } from '@alilc/lowcode-renderer-core';
import { createContext, useContext, type ReactInstance } from 'react';
import { type ReactComponent } from './render';
import { type ReactComponent } from './components';

export const ModelContext = createContext<IComponentTreeModel<ReactComponent, ReactInstance>>(
undefined!,
Expand Down
4 changes: 2 additions & 2 deletions packages/react-renderer/src/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './component';
export * from './render';
export * from './schema';
export * from './components';
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { isValidElementType } from 'react-is';
import { useRenderContext } from '../app/context';
import { reactiveStateFactory } from './reactiveState';
import { dataSourceCreator } from './dataSource';
import { type ReactComponent, type ReactWidget, createElementByWidget } from './render';
import { type ReactComponent, type ReactWidget, createElementByWidget } from './components';
import { ModelContextProvider } from './context';
import { appendExternalStyle } from '../utils/element';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/**
* @vitest-environment jsdom
*/
import { describe, it, expect } from 'vitest';
import { CodeScope } from '../../../src/parts/code-runtime';
import { CodeScope } from '../../../src/services/code-runtime';

describe('CodeScope', () => {
it('should return initial values', () => {
Expand All @@ -18,9 +21,8 @@ describe('CodeScope', () => {
it('inject should not overwrite existing values without force', () => {
const initValue = { a: 1 };
const scope = new CodeScope(initValue);
scope.set('a', 2);
expect(scope.value.a).toBe(1);
scope.set('a', 3, true);
expect(scope.value.a).not.toBe(2);
scope.set('a', 3);
expect(scope.value.a).toBe(3);
});

Expand Down
36 changes: 36 additions & 0 deletions packages/renderer-core/__tests__/services/lifeCycle.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { describe, it, expect } from 'vitest';
import { LifeCycleService, LifecyclePhase } from '../../src/services/lifeCycleService';

const sleep = () => new Promise((r) => setTimeout(r, 500));

describe('LifeCycleService', () => {
it('it works', async () => {
let result = '';
const lifeCycle = new LifeCycleService();

lifeCycle.when(LifecyclePhase.Ready).then(() => {
result += '1';
});
lifeCycle.when(LifecyclePhase.Ready).finally(() => {
result += '2';
});
lifeCycle.when(LifecyclePhase.AfterInitPackageLoad).then(() => {
result += '3';
});
lifeCycle.when(LifecyclePhase.AfterInitPackageLoad).finally(() => {
result += '4';
});

lifeCycle.phase = LifecyclePhase.Ready;

await sleep();

expect(result).toEqual('12');

lifeCycle.phase = LifecyclePhase.AfterInitPackageLoad;

await sleep();

expect(result).toEqual('1234');
});
});
19 changes: 11 additions & 8 deletions packages/renderer-core/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class RendererMain<RenderObject> {
@IBoostsService private boostsService: IBoostsService,
@ILifeCycleService private lifeCycleService: ILifeCycleService,
) {
this.lifeCycleService.when(LifecyclePhase.OptionsResolved).finally(async () => {
this.lifeCycleService.when(LifecyclePhase.OptionsResolved).then(async () => {
const renderContext = {
schema: this.schemaService,
packageManager: this.packageManagementService,
Expand All @@ -42,8 +42,6 @@ export class RendererMain<RenderObject> {

this.renderObject = await this.adapter(renderContext);

await this.packageManagementService.loadPackages(this.initOptions.packages ?? []);

this.lifeCycleService.phase = LifecyclePhase.Ready;
});
}
Expand All @@ -60,13 +58,19 @@ export class RendererMain<RenderObject> {

this.codeRuntimeService.initialize(options.codeRuntime ?? {});

this.extensionHostService.registerPlugin(plugins);

this.lifeCycleService.phase = LifecyclePhase.OptionsResolved;

await this.lifeCycleService.when(LifecyclePhase.Ready);

await this.extensionHostService.registerPlugin(plugins);

await this.packageManagementService.loadPackages(this.initOptions.packages ?? []);

this.lifeCycleService.phase = LifecyclePhase.AfterInitPackageLoad;
}

async getApp(): Promise<RendererApplication<RenderObject>> {
await this.lifeCycleService.when(LifecyclePhase.Ready);
await this.lifeCycleService.when(LifecyclePhase.AfterInitPackageLoad);

// construct application
return Object.freeze<RendererApplication<RenderObject>>({
Expand All @@ -79,8 +83,7 @@ export class RendererMain<RenderObject> {
...this.renderObject,

use: (plugin) => {
this.extensionHostService.registerPlugin(plugin);
return this.extensionHostService.doSetupPlugin(plugin);
return this.extensionHostService.registerPlugin(plugin);
},
});
}
Expand Down
11 changes: 10 additions & 1 deletion packages/renderer-core/src/services/extension/boosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import { ICodeRuntimeService } from '../code-runtime';
import { IRuntimeUtilService } from '../runtimeUtilService';
import { IRuntimeIntlService } from '../runtimeIntlService';

export type IBoosts<Extends> = IBoostsApi & Extends;
export type IBoosts<Extends> = IBoostsApi & Extends & { [key: string]: any };

export interface IBoostsApi {
readonly codeRuntime: ICodeRuntimeService;

readonly intl: Pick<IRuntimeIntlService, 't' | 'setLocale' | 'getLocale' | 'addTranslations'>;

readonly util: Pick<IRuntimeUtilService, 'add' | 'remove'>;
/**
* 允许插件挂载额外的对象在 boosts 上,方便其他插件使用
*/
temporaryUse(name: string, value: any): void;
}

/**
Expand Down Expand Up @@ -43,6 +47,9 @@ export class BoostsService implements IBoostsService {
codeRuntime: this.codeRuntimeService,
intl: this.runtimeIntlService,
util: this.runtimeUtilService,
temporaryUse: (name, value) => {
this.extend(name, value);
},
};
}

Expand All @@ -55,6 +62,8 @@ export class BoostsService implements IBoostsService {
} else {
if (!this.extendsValue[name]) {
this.extendsValue[name] = value;
} else {
console.warn(`${name} is exist`);
}
}
} else if (isObject(name)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@ import { type Plugin, type PluginContext } from './plugin';
import { IBoostsService } from './boosts';
import { IPackageManagementService } from '../package';
import { ISchemaService } from '../schema';
import { type RenderAdapter } from './render';
import { IComponentTreeModelService } from '../model';
import { ILifeCycleService, LifecyclePhase } from '../lifeCycleService';

interface IPluginRuntime extends Plugin {
status: 'setup' | 'ready';
}

export interface IExtensionHostService {
registerPlugin(plugin: Plugin | Plugin[]): void;

doSetupPlugin(plugin: Plugin): Promise<void>;
registerPlugin(plugin: Plugin | Plugin[]): Promise<void>;

getPlugin(name: string): Plugin | undefined;

Expand Down Expand Up @@ -50,15 +46,9 @@ export class ExtensionHostService implements IExtensionHostService {
return this.lifeCycleService.when(phase);
},
};

this.lifeCycleService.when(LifecyclePhase.OptionsResolved).then(async () => {
for (const plugin of this.pluginRuntimes) {
await this.doSetupPlugin(plugin);
}
});
}

registerPlugin(plugins: Plugin | Plugin[]) {
async registerPlugin(plugins: Plugin | Plugin[]) {
plugins = Array.isArray(plugins) ? plugins : [plugins];

for (const plugin of plugins) {
Expand All @@ -67,19 +57,17 @@ export class ExtensionHostService implements IExtensionHostService {
continue;
}

this.pluginRuntimes.push({
...plugin,
status: 'ready',
});
await this.doSetupPlugin(plugin);
}
}

async doSetupPlugin(plugin: Plugin) {
private async doSetupPlugin(plugin: Plugin) {
const pluginRuntime = plugin as IPluginRuntime;

if (!this.pluginRuntimes.some((item) => item.name !== pluginRuntime.name)) {
return;
}
this.pluginRuntimes.push({
...pluginRuntime,
status: 'ready',
});

const isSetup = (name: string) => {
const setupPlugins = this.pluginRuntimes.filter((item) => item.status === 'setup');
Expand Down
Loading

0 comments on commit 61bc8e6

Please sign in to comment.