From 75ce365d2a5f7e2488cca5de6798422399046369 Mon Sep 17 00:00:00 2001 From: Ziheng Gao Date: Thu, 25 Aug 2022 20:26:18 +0800 Subject: [PATCH 1/3] fix(loader): lifecycle loader support named export --- src/loader/impl/lifecycle.ts | 22 ++++++++--- .../{bootstrap.ts => bootstrap_load.ts} | 20 +--------- .../app_with_lifecycle/bootstrap_ready.ts | 37 +++++++++++++++++++ 3 files changed, 55 insertions(+), 24 deletions(-) rename test/fixtures/app_with_lifecycle/{bootstrap.ts => bootstrap_load.ts} (65%) create mode 100644 test/fixtures/app_with_lifecycle/bootstrap_ready.ts diff --git a/src/loader/impl/lifecycle.ts b/src/loader/impl/lifecycle.ts index c1e672d..09d2550 100644 --- a/src/loader/impl/lifecycle.ts +++ b/src/loader/impl/lifecycle.ts @@ -14,12 +14,24 @@ class LifecycleLoader implements Loader { this.container = container; } + get lifecycleManager(): LifecycleManager { + return this.container.get(ArtusInjectEnum.LifecycleManager); + } + async load(item: ManifestItem) { - const extClazz: Constructable = await compatibleRequire(item.path); - const lifecycleManager: LifecycleManager = this.container.get(ArtusInjectEnum.LifecycleManager); - this.container.set({ type: extClazz }); - lifecycleManager.registerHookUnit(extClazz); - return extClazz; + const origin: Constructable[] = await compatibleRequire(item.path, true); + item._loaderState = Object.assign({ exportNames: ['default'] }, item._loaderState); + const { _loaderState: state } = item as { _loaderState: { exportNames: string[] } }; + + const lifecycleClazzList = []; + + for (const name of state.exportNames) { + const clazz = origin[name]; + this.container.set({ type: clazz }); + this.lifecycleManager.registerHookUnit(clazz); + } + + return lifecycleClazzList; } } diff --git a/test/fixtures/app_with_lifecycle/bootstrap.ts b/test/fixtures/app_with_lifecycle/bootstrap_load.ts similarity index 65% rename from test/fixtures/app_with_lifecycle/bootstrap.ts rename to test/fixtures/app_with_lifecycle/bootstrap_load.ts index 97aad97..7590f3f 100644 --- a/test/fixtures/app_with_lifecycle/bootstrap.ts +++ b/test/fixtures/app_with_lifecycle/bootstrap_load.ts @@ -8,7 +8,7 @@ import LifecycleList from './lifecyclelist'; export const TEST_LIFE_CYCLE_LIST = 'TEST_LIFE_CYCLE_LIST'; @LifecycleHookUnit() -export default class AppLifecycle implements ApplicationLifecycle { +export default class AppLoadLifecycle implements ApplicationLifecycle { @Inject(ArtusInjectEnum.Application) app: ArtusApplication; @@ -36,22 +36,4 @@ export default class AppLifecycle implements ApplicationLifecycle { await new Promise(resolve => setTimeout(resolve, 100)); this.lifecycleList.add('app_didLoad'); } - - @LifecycleHook('willReady') - async willReady() { - await new Promise(resolve => setTimeout(resolve, 100)); - this.lifecycleList.add('app_willReady'); - } - - @LifecycleHook('didReady') - async didReady() { - await new Promise(resolve => setTimeout(resolve, 100)); - this.lifecycleList.add('app_didReady'); - } - - @LifecycleHook() - async beforeClose() { - await new Promise(resolve => setTimeout(resolve, 100)); - this.lifecycleList.add('app_beforeClose'); - } } diff --git a/test/fixtures/app_with_lifecycle/bootstrap_ready.ts b/test/fixtures/app_with_lifecycle/bootstrap_ready.ts new file mode 100644 index 0000000..9f0d7b4 --- /dev/null +++ b/test/fixtures/app_with_lifecycle/bootstrap_ready.ts @@ -0,0 +1,37 @@ +import { + ArtusApplication, + ApplicationLifecycle, LifecycleHookUnit, LifecycleHook, ArtusInjectEnum, +} from '../../../src/index'; + +import { Container, Inject } from '@artus/injection'; +import LifecycleList from './lifecyclelist'; + +@LifecycleHookUnit() +export class AppReadyLifecycle implements ApplicationLifecycle { + @Inject(ArtusInjectEnum.Application) + app: ArtusApplication; + + @Inject() + container: Container; + + @Inject() + lifecycleList: LifecycleList; + + @LifecycleHook('willReady') + async willReady() { + await new Promise(resolve => setTimeout(resolve, 100)); + this.lifecycleList.add('app_willReady'); + } + + @LifecycleHook('didReady') + async didReady() { + await new Promise(resolve => setTimeout(resolve, 100)); + this.lifecycleList.add('app_didReady'); + } + + @LifecycleHook() + async beforeClose() { + await new Promise(resolve => setTimeout(resolve, 100)); + this.lifecycleList.add('app_beforeClose'); + } +} From f3daa1a0832f4914f8aa7d8c3929341dadddd7db Mon Sep 17 00:00:00 2001 From: Ziheng Gao Date: Thu, 25 Aug 2022 20:33:29 +0800 Subject: [PATCH 2/3] fix(lifecycle): hook-unit can be registered once only --- src/lifecycle/index.ts | 7 ++++++- test/fixtures/app_with_lifecycle/bootstrap_duplicated.ts | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/app_with_lifecycle/bootstrap_duplicated.ts diff --git a/src/lifecycle/index.ts b/src/lifecycle/index.ts index c83f216..fd7dcd3 100644 --- a/src/lifecycle/index.ts +++ b/src/lifecycle/index.ts @@ -1,5 +1,5 @@ import { Constructable, Container } from '@artus/injection'; -import { Application } from '../types'; +import { Application, ApplicationLifecycle } from '../types'; import { HOOK_NAME_META_PREFIX, } from '../constant'; @@ -22,6 +22,7 @@ export class LifecycleManager { hookFnMap: Map = new Map(); private app: Application; private container: Container; + private hookUnitSet: Set> = new Set(); constructor(app: Application, container: Container) { this.app = app; @@ -48,6 +49,10 @@ export class LifecycleManager { } registerHookUnit(extClazz: Constructable) { + if (this.hookUnitSet.has(extClazz)) { + return; + } + this.hookUnitSet.add(extClazz); const fnMetaKeys = Reflect.getMetadataKeys(extClazz); const extClazzInstance = this.container.get(extClazz); for (const fnMetaKey of fnMetaKeys) { diff --git a/test/fixtures/app_with_lifecycle/bootstrap_duplicated.ts b/test/fixtures/app_with_lifecycle/bootstrap_duplicated.ts new file mode 100644 index 0000000..166a7ae --- /dev/null +++ b/test/fixtures/app_with_lifecycle/bootstrap_duplicated.ts @@ -0,0 +1 @@ +export * from './bootstrap_ready'; From 4de4121f01fdc02b39e03485a6d36170bdd745b8 Mon Sep 17 00:00:00 2001 From: Ziheng Gao Date: Thu, 25 Aug 2022 20:34:48 +0800 Subject: [PATCH 3/3] chore: replace loaderState as public value --- src/loader/factory.ts | 2 +- src/loader/impl/lifecycle.ts | 4 ++-- src/loader/impl/module.ts | 4 ++-- src/loader/impl/plugin_config.ts | 2 +- src/loader/types.ts | 2 +- src/scanner/scan.ts | 2 +- src/scanner/utils.ts | 2 +- test/fixtures/module_with_custom_loader/src/index.ts | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/loader/factory.ts b/src/loader/factory.ts index ccb744e..2963164 100644 --- a/src/loader/factory.ts +++ b/src/loader/factory.ts @@ -88,7 +88,7 @@ export class LoaderFactory { loadItem(item: ManifestItem): Promise { const loaderName = item.loader || DEFAULT_LOADER; const loader = this.getLoader(loaderName); - loader.state = item._loaderState; + loader.state = item.loaderState; return loader.load(item); } diff --git a/src/loader/impl/lifecycle.ts b/src/loader/impl/lifecycle.ts index 09d2550..59e88cc 100644 --- a/src/loader/impl/lifecycle.ts +++ b/src/loader/impl/lifecycle.ts @@ -20,8 +20,8 @@ class LifecycleLoader implements Loader { async load(item: ManifestItem) { const origin: Constructable[] = await compatibleRequire(item.path, true); - item._loaderState = Object.assign({ exportNames: ['default'] }, item._loaderState); - const { _loaderState: state } = item as { _loaderState: { exportNames: string[] } }; + item.loaderState = Object.assign({ exportNames: ['default'] }, item.loaderState); + const { loaderState: state } = item as { loaderState: { exportNames: string[] } }; const lifecycleClazzList = []; diff --git a/src/loader/impl/module.ts b/src/loader/impl/module.ts index ba2e989..80e9a26 100644 --- a/src/loader/impl/module.ts +++ b/src/loader/impl/module.ts @@ -14,8 +14,8 @@ class ModuleLoader implements Loader { async load(item: ManifestItem): Promise { const origin = await compatibleRequire(item.path, true); - item._loaderState = Object.assign({ exportNames: ['default'] }, item._loaderState); - const { _loaderState: state } = item as { _loaderState: { exportNames: string[] } }; + item.loaderState = Object.assign({ exportNames: ['default'] }, item.loaderState); + const { loaderState: state } = item as { loaderState: { exportNames: string[] } }; const modules: Constructable[] = []; diff --git a/src/loader/impl/plugin_config.ts b/src/loader/impl/plugin_config.ts index 365fb55..aa16eb5 100644 --- a/src/loader/impl/plugin_config.ts +++ b/src/loader/impl/plugin_config.ts @@ -28,7 +28,7 @@ class PluginConfigLoader extends ConfigLoader implements Loader { `Plugin ${pluginName} config can't have both package and path at ${item.path}`, ); } - const loaderState = item._loaderState as { baseDir: string }; + const loaderState = item.loaderState as { baseDir: string }; pluginConfigItem.path = ArtusPlugin.getPath(pluginConfigItem.package, [loaderState?.baseDir]); delete pluginConfigItem.package; configObj[pluginName] = pluginConfigItem; diff --git a/src/loader/types.ts b/src/loader/types.ts index 5e1ddc2..a3d82e4 100644 --- a/src/loader/types.ts +++ b/src/loader/types.ts @@ -13,7 +13,7 @@ interface ManifestItem extends Record { loader?: string; source?: string; unitName?: string; - _loaderState?: LoaderState; + loaderState?: LoaderState; } interface LoaderFindOptions { diff --git a/src/scanner/scan.ts b/src/scanner/scan.ts index a6af857..72c6c00 100644 --- a/src/scanner/scan.ts +++ b/src/scanner/scan.ts @@ -188,7 +188,7 @@ export class Scanner { filename, loader, source: 'config', - _loaderState: { + loaderState: { baseDir, }, }; diff --git a/src/scanner/utils.ts b/src/scanner/utils.ts index bd97463..a2b3d87 100644 --- a/src/scanner/utils.ts +++ b/src/scanner/utils.ts @@ -71,7 +71,7 @@ export class ScanUtils { source, }; if (loaderState) { - item._loaderState = loaderState; + item.loaderState = loaderState; } unitName && (item.unitName = unitName); const itemList = options.itemMap.get(item.loader ?? DEFAULT_LOADER); diff --git a/test/fixtures/module_with_custom_loader/src/index.ts b/test/fixtures/module_with_custom_loader/src/index.ts index af0d2c7..64354e8 100644 --- a/test/fixtures/module_with_custom_loader/src/index.ts +++ b/test/fixtures/module_with_custom_loader/src/index.ts @@ -11,7 +11,7 @@ export default ({ extname: '.ts', filename: 'test_clazz.ts', loader: 'test-custom-loader', - _loaderState: { + loaderState: { hello: 'loaderState', }, },