mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-11 18:42:56 +00:00
fix: lifeCycle events and router plugin
This commit is contained in:
parent
37d07f1db6
commit
61bc8e6c3d
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,7 +13,6 @@ pnpm-lock.yaml
|
||||
deploy-space/packages
|
||||
deploy-space/.env
|
||||
|
||||
|
||||
# IDE
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
@ -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>;
|
||||
@ -17,7 +17,7 @@ export const createApp = async (options: ReactAppOptions) => {
|
||||
// }
|
||||
|
||||
// extends boosts
|
||||
extension.install(boostsManager);
|
||||
boostsManager.extend(boosts.toExpose());
|
||||
|
||||
let root: Root | undefined;
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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>>;
|
||||
@ -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;
|
||||
@ -28,7 +28,7 @@ class ReactRendererExtension {
|
||||
return this.outlet;
|
||||
}
|
||||
|
||||
toExpose(): ReactRendererExtensionApi {
|
||||
toExpose(): ReactRendererBoostsApi {
|
||||
return {
|
||||
addAppWrapper: (appWrapper) => {
|
||||
if (appWrapper) this.wrappers.push(appWrapper);
|
||||
@ -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;
|
||||
}
|
||||
@ -1,3 +1,3 @@
|
||||
export * from './context';
|
||||
export * from './extension';
|
||||
export * from './boosts';
|
||||
export * from './view';
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,2 +1,3 @@
|
||||
export * from './context';
|
||||
export * from './plugin';
|
||||
export type * from '@alilc/lowcode-renderer-router';
|
||||
|
||||
@ -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';
|
||||
@ -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();
|
||||
});
|
||||
},
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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>;
|
||||
@ -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!,
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
export * from './component';
|
||||
export * from './render';
|
||||
export * from './schema';
|
||||
export * from './components';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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', () => {
|
||||
@ -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);
|
||||
});
|
||||
|
||||
36
packages/renderer-core/__tests__/services/lifeCycle.spec.ts
Normal file
36
packages/renderer-core/__tests__/services/lifeCycle.spec.ts
Normal file
@ -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');
|
||||
});
|
||||
});
|
||||
@ -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,
|
||||
@ -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;
|
||||
});
|
||||
}
|
||||
@ -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>>({
|
||||
@ -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);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ 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;
|
||||
@ -12,6 +12,10 @@ export interface IBoostsApi {
|
||||
readonly intl: Pick<IRuntimeIntlService, 't' | 'setLocale' | 'getLocale' | 'addTranslations'>;
|
||||
|
||||
readonly util: Pick<IRuntimeUtilService, 'add' | 'remove'>;
|
||||
/**
|
||||
* 允许插件挂载额外的对象在 boosts 上,方便其他插件使用
|
||||
*/
|
||||
temporaryUse(name: string, value: any): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -3,8 +3,6 @@ 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 {
|
||||
@ -12,9 +10,7 @@ interface IPluginRuntime extends Plugin {
|
||||
}
|
||||
|
||||
export interface IExtensionHostService {
|
||||
registerPlugin(plugin: Plugin | Plugin[]): void;
|
||||
|
||||
doSetupPlugin(plugin: Plugin): Promise<void>;
|
||||
registerPlugin(plugin: Plugin | Plugin[]): Promise<void>;
|
||||
|
||||
getPlugin(name: string): Plugin | undefined;
|
||||
|
||||
@ -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) {
|
||||
@ -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');
|
||||
|
||||
@ -7,11 +7,7 @@ export const enum LifecyclePhase {
|
||||
|
||||
Ready = 3,
|
||||
|
||||
BeforeMount = 4,
|
||||
|
||||
Mounted = 5,
|
||||
|
||||
BeforeUnmount = 6,
|
||||
AfterInitPackageLoad = 4,
|
||||
}
|
||||
|
||||
export interface ILifeCycleService {
|
||||
@ -40,7 +36,7 @@ export class LifeCycleService implements ILifeCycleService {
|
||||
}
|
||||
|
||||
set phase(value: LifecyclePhase) {
|
||||
if (value < this.phase) {
|
||||
if (value < this._phase) {
|
||||
throw new Error('Lifecycle cannot go backwards');
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ export class PackageManagementService implements IPackageManagementService {
|
||||
@ISchemaService private schemaService: ISchemaService,
|
||||
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
||||
) {
|
||||
this.lifeCycleService.when(LifecyclePhase.Ready).then(() => {
|
||||
this.lifeCycleService.when(LifecyclePhase.AfterInitPackageLoad).then(() => {
|
||||
const componentsMaps = this.schemaService.get('componentsMap');
|
||||
this.resolveComponentMaps(componentsMaps);
|
||||
});
|
||||
@ -85,7 +85,6 @@ export class PackageManagementService implements IPackageManagementService {
|
||||
if (!isProCodeComponentPackage(item)) continue;
|
||||
|
||||
const normalized = this.normalizePackage(item);
|
||||
|
||||
await this.loadPackageByNormalized(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
type Spec,
|
||||
type Locale,
|
||||
type Translations,
|
||||
platformLocale,
|
||||
} from '@alilc/lowcode-shared';
|
||||
import { ILifeCycleService, LifecyclePhase } from './lifeCycleService';
|
||||
import { ICodeRuntimeService } from './code-runtime';
|
||||
@ -34,7 +35,7 @@ export const IRuntimeIntlService = createDecorator<IRuntimeIntlService>('IRuntim
|
||||
export class RuntimeIntlService implements IRuntimeIntlService {
|
||||
private intl: Intl = new Intl();
|
||||
|
||||
public locale: string = navigator.language;
|
||||
public locale: string = platformLocale;
|
||||
|
||||
constructor(
|
||||
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
||||
|
||||
@ -23,12 +23,11 @@ export class RuntimeUtilService implements IRuntimeUtilService {
|
||||
@ILifeCycleService private lifeCycleService: ILifeCycleService,
|
||||
@ISchemaService private schemaService: ISchemaService,
|
||||
) {
|
||||
this.lifeCycleService.when(LifecyclePhase.Ready).then(() => {
|
||||
this.lifeCycleService.when(LifecyclePhase.AfterInitPackageLoad).then(() => {
|
||||
const utils = this.schemaService.get('utils') ?? [];
|
||||
for (const util of utils) {
|
||||
this.add(util);
|
||||
}
|
||||
|
||||
this.toExpose();
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import { defineProject } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
export default defineProject({
|
||||
test: {
|
||||
include: ['tests/**/*.spec.ts']
|
||||
}
|
||||
})
|
||||
environment: 'jsdom',
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { EventEmitter } from '../../src';
|
||||
|
||||
describe('hookable', () => {
|
||||
let eventEmitter: EventEmitter;
|
||||
|
||||
beforeEach(() => {
|
||||
eventEmitter = new EventEmitter();
|
||||
});
|
||||
|
||||
it('on', async () => {
|
||||
const spy = vi.fn();
|
||||
eventEmitter.on('test', spy);
|
||||
await eventEmitter.emit('test');
|
||||
|
||||
expect(spy).toBeCalled();
|
||||
});
|
||||
|
||||
it('prependListener', () => {
|
||||
// const spy = vi.fn();
|
||||
// expect(spy).toC
|
||||
});
|
||||
});
|
||||
56
packages/shared/__tests__/utils/async.spec.ts
Normal file
56
packages/shared/__tests__/utils/async.spec.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { Barrier } from '../../src';
|
||||
|
||||
describe('Barrier', () => {
|
||||
it('waits for barrier to open', async () => {
|
||||
const barrier = new Barrier();
|
||||
|
||||
setTimeout(() => {
|
||||
barrier.open();
|
||||
}, 500); // Simulate opening the barrier after 500ms
|
||||
|
||||
const start = Date.now();
|
||||
await barrier.wait(); // Async operation should await here
|
||||
const duration = Date.now() - start;
|
||||
|
||||
expect(barrier.isOpen()).toBeTruthy();
|
||||
expect(duration).toBeGreaterThanOrEqual(500); // Ensures we waited for at least 500ms
|
||||
});
|
||||
|
||||
it('mutiple', async () => {
|
||||
let result = '';
|
||||
const b1 = new Barrier();
|
||||
const b2 = new Barrier();
|
||||
|
||||
async function run1() {
|
||||
await b1.wait();
|
||||
}
|
||||
async function run2() {
|
||||
await b2.wait();
|
||||
}
|
||||
|
||||
run1().then(() => {
|
||||
result += 1;
|
||||
});
|
||||
run1().finally(() => {
|
||||
result += 2;
|
||||
});
|
||||
|
||||
run2().then(() => {
|
||||
result += 3;
|
||||
});
|
||||
run2().finally(() => {
|
||||
result += 4;
|
||||
});
|
||||
|
||||
b1.open();
|
||||
|
||||
await run1();
|
||||
|
||||
b2.open();
|
||||
|
||||
await run2();
|
||||
|
||||
expect(result).toBe('1234');
|
||||
});
|
||||
});
|
||||
@ -5,6 +5,13 @@
|
||||
"main": "dist/low-code-shared.cjs",
|
||||
"module": "dist/low-code-shared.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/low-code-shared.js",
|
||||
"require": "./dist/low-code-shared.cjs",
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
|
||||
@ -15,7 +15,7 @@ export type Constructor<T = any> = new (...args: any[]) => T;
|
||||
export function createDecorator<T>(serviceId: string): ServiceIdentifier<T> {
|
||||
const id = <any>(
|
||||
function (target: Constructor, targetKey: string, indexOrPropertyDescriptor: any): any {
|
||||
return set(serviceId)(target, targetKey, indexOrPropertyDescriptor);
|
||||
return inject(serviceId)(target, targetKey, indexOrPropertyDescriptor);
|
||||
}
|
||||
);
|
||||
id.toString = () => serviceId;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { createIntl, createIntlCache, type IntlShape as IntlFormatter } from '@formatjs/intl';
|
||||
import { mapKeys } from 'lodash-es';
|
||||
import { signal, computed, effect, type Signal, type ComputedSignal } from '../signals';
|
||||
import { platformLocale } from '../utils';
|
||||
|
||||
export { IntlFormatter };
|
||||
|
||||
@ -14,7 +15,7 @@ export class Intl {
|
||||
private currentMessage: ComputedSignal<Translations>;
|
||||
private intlShape: IntlFormatter;
|
||||
|
||||
constructor(defaultLocale: string = navigator.language, messages: LocaleTranslationsRecord = {}) {
|
||||
constructor(defaultLocale: string = platformLocale, messages: LocaleTranslationsRecord = {}) {
|
||||
if (defaultLocale) {
|
||||
defaultLocale = nomarlizeLocale(defaultLocale);
|
||||
} else {
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
const userAgent: string = navigator.userAgent;
|
||||
const userAgent: string = window.navigator.userAgent;
|
||||
|
||||
export const isWindows = userAgent.indexOf('Windows') >= 0;
|
||||
export const isMacintosh = userAgent.indexOf('Macintosh') >= 0;
|
||||
export const isLinux = userAgent.indexOf('Linux') >= 0;
|
||||
export const isIOS =
|
||||
(isMacintosh || userAgent.indexOf('iPad') >= 0 || userAgent.indexOf('iPhone') >= 0) &&
|
||||
!!navigator.maxTouchPoints &&
|
||||
navigator.maxTouchPoints > 0;
|
||||
!!window.navigator.maxTouchPoints &&
|
||||
window.navigator.maxTouchPoints > 0;
|
||||
export const isMobile = userAgent?.indexOf('Mobi') >= 0;
|
||||
export const locale: string | undefined = undefined;
|
||||
export const platformLocale = navigator.language;
|
||||
|
||||
export const platformLocale = window.navigator.language;
|
||||
|
||||
export const enum Platform {
|
||||
Web,
|
||||
|
||||
3
packages/shared/vitest.config.ts
Normal file
3
packages/shared/vitest.config.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { defineProject } from 'vitest/config';
|
||||
|
||||
export default defineProject({});
|
||||
@ -1,5 +1,5 @@
|
||||
packages:
|
||||
- 'packages/*'
|
||||
- 'playground'
|
||||
- 'playground/*'
|
||||
- 'docs'
|
||||
- 'scripts'
|
||||
|
||||
@ -39,5 +39,11 @@
|
||||
},
|
||||
"types": ["vite/client", "vitest/globals", "node"]
|
||||
},
|
||||
"exclude": ["**/dist", "node_modules"]
|
||||
"include": [
|
||||
"packages/global.d.ts",
|
||||
"packages/*/src",
|
||||
"packages/*/__tests__",
|
||||
"playground/*/src",
|
||||
"scripts/*"
|
||||
]
|
||||
}
|
||||
|
||||
@ -5,9 +5,12 @@ export default defineWorkspace([
|
||||
{
|
||||
test: {
|
||||
include: ['**/__tests__/**/*.spec.{ts?(x),js?(x)}'],
|
||||
alias: {
|
||||
'@alilc/lowcode-shared': 'packages/shared',
|
||||
},
|
||||
name: 'unit test',
|
||||
environment: 'jsdom',
|
||||
globals: true
|
||||
}
|
||||
environmentMatchGlobs: [['packages/**', 'jsdom']],
|
||||
globals: true,
|
||||
},
|
||||
},
|
||||
])
|
||||
]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user