plugin.module.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { DynamicModule, Inject, Module, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
  2. import { ModuleRef } from '@nestjs/core';
  3. import { getConfig } from '../config/config-helpers';
  4. import { ConfigModule } from '../config/config.module';
  5. import { ConfigService } from '../config/config.service';
  6. import { Logger } from '../config/logger/vendure-logger';
  7. import {
  8. getPluginModules,
  9. getWorkerControllers,
  10. hasLifecycleMethod,
  11. isDynamicModule,
  12. } from './plugin-metadata';
  13. import { PluginLifecycleMethods } from './vendure-plugin';
  14. export enum PluginProcessContext {
  15. Main,
  16. Worker,
  17. }
  18. const PLUGIN_PROCESS_CONTEXT = 'PLUGIN_PROCESS_CONTEXT';
  19. /**
  20. * This module collects and re-exports all providers defined in plugins so that they can be used in other
  21. * modules and in responsible for executing any lifecycle methods defined by the plugins.
  22. */
  23. @Module({
  24. imports: [ConfigModule],
  25. })
  26. export class PluginModule implements OnModuleInit, OnModuleDestroy {
  27. static forRoot(): DynamicModule {
  28. return {
  29. module: PluginModule,
  30. providers: [{ provide: PLUGIN_PROCESS_CONTEXT, useValue: PluginProcessContext.Main }],
  31. imports: [...getConfig().plugins],
  32. };
  33. }
  34. static forWorker(): DynamicModule {
  35. return {
  36. module: PluginModule,
  37. providers: [{ provide: PLUGIN_PROCESS_CONTEXT, useValue: PluginProcessContext.Worker }],
  38. imports: [...pluginsWithWorkerControllers()],
  39. };
  40. }
  41. constructor(
  42. @Inject(PLUGIN_PROCESS_CONTEXT) private processContext: PluginProcessContext,
  43. private moduleRef: ModuleRef,
  44. private configService: ConfigService,
  45. ) {}
  46. async onModuleInit() {
  47. if (this.processContext === PluginProcessContext.Main) {
  48. await this.runPluginLifecycleMethods('onVendureBootstrap', instance => {
  49. const pluginName = instance.constructor.name || '(anonymous plugin)';
  50. Logger.verbose(`Bootstrapped plugin ${pluginName}`);
  51. });
  52. }
  53. if (this.processContext === PluginProcessContext.Worker) {
  54. await this.runPluginLifecycleMethods('onVendureWorkerBootstrap');
  55. }
  56. }
  57. async onModuleDestroy() {
  58. if (this.processContext === PluginProcessContext.Main) {
  59. await this.runPluginLifecycleMethods('onVendureClose');
  60. }
  61. if (this.processContext === PluginProcessContext.Worker) {
  62. await this.runPluginLifecycleMethods('onVendureWorkerClose');
  63. }
  64. }
  65. private async runPluginLifecycleMethods(
  66. lifecycleMethod: keyof PluginLifecycleMethods,
  67. afterRun?: (instance: any) => void,
  68. ) {
  69. for (const plugin of getPluginModules(this.configService.plugins)) {
  70. let instance: any;
  71. try {
  72. instance = this.moduleRef.get(plugin, { strict: false });
  73. } catch (e) {
  74. Logger.error(`Could not find ${plugin.name}`, undefined, e.stack);
  75. }
  76. if (instance) {
  77. if (hasLifecycleMethod(instance, lifecycleMethod)) {
  78. await instance[lifecycleMethod]();
  79. }
  80. if (typeof afterRun === 'function') {
  81. afterRun(instance);
  82. }
  83. }
  84. }
  85. }
  86. }
  87. function pluginsWithWorkerControllers(): DynamicModule[] {
  88. return getConfig().plugins.map(plugin => {
  89. const controllers = getWorkerControllers(plugin);
  90. if (isDynamicModule(plugin)) {
  91. return {
  92. ...plugin,
  93. controllers,
  94. };
  95. } else {
  96. return {
  97. module: plugin,
  98. controllers,
  99. };
  100. }
  101. });
  102. }