Explorar o código

feat(email-plugin): EmailGenerator now implements InjectableStrategy

Relates to #1767
Michael Bromley %!s(int64=3) %!d(string=hai) anos
pai
achega
f9aa5d747d

+ 1 - 0
packages/email-plugin/index.ts

@@ -7,3 +7,4 @@ export * from './src/noop-email-generator';
 export * from './src/plugin';
 export * from './src/template-loader';
 export * from './src/types';
+export * from './src/email-generator';

+ 32 - 0
packages/email-plugin/src/email-generator.ts

@@ -0,0 +1,32 @@
+import { InjectableStrategy, VendureEvent } from '@vendure/core';
+
+import { EmailDetails, EmailPluginOptions } from './types';
+
+/**
+ * @description
+ * An EmailGenerator generates the subject and body details of an email.
+ *
+ * @docsCategory EmailPlugin
+ * @docsPage EmailGenerator
+ * @docsWeight 0
+ */
+export interface EmailGenerator<T extends string = any, E extends VendureEvent = any>
+    extends InjectableStrategy {
+    /**
+     * @description
+     * Any necessary setup can be performed here.
+     */
+    onInit?(options: EmailPluginOptions): void | Promise<void>;
+
+    /**
+     * @description
+     * Given a subject and body from an email template, this method generates the final
+     * interpolated email text.
+     */
+    generate(
+        from: string,
+        subject: string,
+        body: string,
+        templateVars: { [key: string]: any },
+    ): Pick<EmailDetails, 'from' | 'subject' | 'body'>;
+}

+ 1 - 1
packages/email-plugin/src/email-processor.ts

@@ -5,12 +5,12 @@ import fs from 'fs-extra';
 import { deserializeAttachments } from './attachment-utils';
 import { isDevModeOptions } from './common';
 import { EMAIL_PLUGIN_OPTIONS, loggerCtx } from './constants';
+import { EmailGenerator } from './email-generator';
 import { HandlebarsMjmlGenerator } from './handlebars-mjml-generator';
 import { NodemailerEmailSender } from './nodemailer-email-sender';
 import { TemplateLoader } from './template-loader';
 import {
     EmailDetails,
-    EmailGenerator,
     EmailPluginOptions,
     EmailSender,
     EmailTransportOptions,

+ 2 - 1
packages/email-plugin/src/handlebars-mjml-generator.ts

@@ -3,8 +3,9 @@ import fs from 'fs-extra';
 import Handlebars from 'handlebars';
 import mjml2html from 'mjml';
 import path from 'path';
+import { EmailGenerator } from './email-generator';
 
-import { EmailGenerator, EmailPluginDevModeOptions, EmailPluginOptions } from './types';
+import { EmailPluginDevModeOptions, EmailPluginOptions } from './types';
 
 /**
  * @description

+ 1 - 1
packages/email-plugin/src/noop-email-generator.ts

@@ -1,4 +1,4 @@
-import { EmailGenerator } from './types';
+import { EmailGenerator } from './email-generator';
 
 /**
  * Simply passes through the subject and template content without modification.

+ 32 - 11
packages/email-plugin/src/plugin.ts

@@ -1,4 +1,10 @@
-import { MiddlewareConsumer, NestModule, OnApplicationBootstrap } from '@nestjs/common';
+import {
+    Inject,
+    MiddlewareConsumer,
+    NestModule,
+    OnApplicationBootstrap,
+    OnApplicationShutdown,
+} from '@nestjs/common';
 import { ModuleRef } from '@nestjs/core';
 import {
     EventBus,
@@ -228,7 +234,7 @@ import {
     imports: [PluginCommonModule],
     providers: [{ provide: EMAIL_PLUGIN_OPTIONS, useFactory: () => EmailPlugin.options }, EmailProcessor],
 })
-export class EmailPlugin implements OnApplicationBootstrap, NestModule {
+export class EmailPlugin implements OnApplicationBootstrap, OnApplicationShutdown, NestModule {
     private static options: EmailPluginOptions | EmailPluginDevModeOptions;
     private devMailbox: DevMailbox | undefined;
     private jobQueue: JobQueue<IntermediateEmailDetails> | undefined;
@@ -241,6 +247,7 @@ export class EmailPlugin implements OnApplicationBootstrap, NestModule {
         private emailProcessor: EmailProcessor,
         private jobQueueService: JobQueueService,
         private processContext: ProcessContext,
+        @Inject(EMAIL_PLUGIN_OPTIONS) private options: EmailPluginOptions,
     ) {}
 
     /**
@@ -253,13 +260,12 @@ export class EmailPlugin implements OnApplicationBootstrap, NestModule {
 
     /** @internal */
     async onApplicationBootstrap(): Promise<void> {
-        const options = EmailPlugin.options;
-
+        await this.initInjectableStrategies();
         await this.setupEventSubscribers();
-        if (!isDevModeOptions(options) && options.transport.type === 'testing') {
+        if (!isDevModeOptions(this.options) && this.options.transport.type === 'testing') {
             // When running tests, we don't want to go through the JobQueue system,
             // so we just call the email sending logic directly.
-            this.testingProcessor = new EmailProcessor(options);
+            this.testingProcessor = new EmailProcessor(this.options);
             await this.testingProcessor.init();
         } else {
             await this.emailProcessor.init();
@@ -272,15 +278,30 @@ export class EmailPlugin implements OnApplicationBootstrap, NestModule {
         }
     }
 
-    configure(consumer: MiddlewareConsumer) {
-        const options = EmailPlugin.options;
+    async onApplicationShutdown() {
+        await this.destroyInjectableStrategies();
+    }
 
-        if (isDevModeOptions(options) && this.processContext.isServer) {
+    configure(consumer: MiddlewareConsumer) {
+        if (isDevModeOptions(this.options) && this.processContext.isServer) {
             Logger.info('Creating dev mailbox middleware', loggerCtx);
             this.devMailbox = new DevMailbox();
-            consumer.apply(this.devMailbox.serve(options)).forRoutes(options.route);
+            consumer.apply(this.devMailbox.serve(this.options)).forRoutes(this.options.route);
             this.devMailbox.handleMockEvent((handler, event) => this.handleEvent(handler, event));
-            registerPluginStartupMessage('Dev mailbox', options.route);
+            registerPluginStartupMessage('Dev mailbox', this.options.route);
+        }
+    }
+
+    private async initInjectableStrategies() {
+        const injector = new Injector(this.moduleRef);
+        if (typeof this.options.emailGenerator?.init === 'function') {
+            await this.options.emailGenerator.init(injector);
+        }
+    }
+
+    private async destroyInjectableStrategies() {
+        if (typeof this.options.emailGenerator?.destroy === 'function') {
+            await this.options.emailGenerator.destroy();
         }
     }
 

+ 1 - 28
packages/email-plugin/src/types.ts

@@ -4,6 +4,7 @@ import { Injector, RequestContext, VendureEvent } from '@vendure/core';
 import { Attachment } from 'nodemailer/lib/mailer';
 import SMTPTransport from 'nodemailer/lib/smtp-transport';
 
+import { EmailGenerator } from './email-generator';
 import { EmailEventHandler } from './event-handler';
 
 /**
@@ -251,34 +252,6 @@ export interface EmailSender {
     send: (email: EmailDetails, options: EmailTransportOptions) => void | Promise<void>;
 }
 
-/**
- * @description
- * An EmailGenerator generates the subject and body details of an email.
- *
- * @docsCategory EmailPlugin
- * @docsPage EmailGenerator
- * @docsWeight 0
- */
-export interface EmailGenerator<T extends string = any, E extends VendureEvent = any> {
-    /**
-     * @description
-     * Any necessary setup can be performed here.
-     */
-    onInit?(options: EmailPluginOptions): void | Promise<void>;
-
-    /**
-     * @description
-     * Given a subject and body from an email template, this method generates the final
-     * interpolated email text.
-     */
-    generate(
-        from: string,
-        subject: string,
-        body: string,
-        templateVars: { [key: string]: any },
-    ): Pick<EmailDetails, 'from' | 'subject' | 'body'>;
-}
-
 /**
  * @description
  * A function used to load async data for use by an {@link EmailEventHandler}.