From 755b687d48f530606ded25abe28ac7b0610b8217 Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Thu, 11 Sep 2025 10:09:04 -0300 Subject: [PATCH 1/7] use a single `render` function --- src/batch/batch.ts | 15 ++------------- src/emails/emails.ts | 15 ++------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/batch/batch.ts b/src/batch/batch.ts index cf0a3b6b..848a7037 100644 --- a/src/batch/batch.ts +++ b/src/batch/batch.ts @@ -7,9 +7,9 @@ import type { CreateBatchResponse, CreateBatchSuccessResponse, } from './interfaces/create-batch-options.interface'; +import { render } from '../render'; export class Batch { - private renderAsync?: (component: React.ReactElement) => Promise; constructor(private readonly resend: Resend) {} async send( @@ -27,18 +27,7 @@ export class Batch { for (const email of payload) { if (email.react) { - if (!this.renderAsync) { - try { - const { renderAsync } = await import('@react-email/render'); - this.renderAsync = renderAsync; - } catch { - throw new Error( - 'Failed to render React component. Make sure to install `@react-email/render`', - ); - } - } - - email.html = await this.renderAsync(email.react as React.ReactElement); + email.html = await render(email.react); email.react = undefined; } diff --git a/src/emails/emails.ts b/src/emails/emails.ts index 37e4533b..311574d2 100644 --- a/src/emails/emails.ts +++ b/src/emails/emails.ts @@ -26,9 +26,9 @@ import type { UpdateEmailResponse, UpdateEmailResponseSuccess, } from './interfaces/update-email-options.interface'; +import { render } from '../render'; export class Emails { - private renderAsync?: (component: React.ReactElement) => Promise; constructor(private readonly resend: Resend) {} async send( @@ -43,18 +43,7 @@ export class Emails { options: CreateEmailRequestOptions = {}, ): Promise { if (payload.react) { - if (!this.renderAsync) { - try { - const { renderAsync } = await import('@react-email/render'); - this.renderAsync = renderAsync; - } catch { - throw new Error( - 'Failed to render React component. Make sure to install `@react-email/render`', - ); - } - } - - payload.html = await this.renderAsync( + payload.html = await render( payload.react as React.ReactElement, ); } From d291453e1fa6a924ba7553f1cd4a40f7a8eb3512 Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Thu, 11 Sep 2025 10:09:31 -0300 Subject: [PATCH 2/7] add render function with the then-catch callback syntax --- src/render.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/render.ts diff --git a/src/render.ts b/src/render.ts new file mode 100644 index 00000000..7b80f16f --- /dev/null +++ b/src/render.ts @@ -0,0 +1,18 @@ +export function render(node: React.ReactNode) { + return new Promise((resolve, reject) => { + // we don't use async here, because tsup transpiles it to + // using a generator syntax that, if used in conjunction + // with a bundler on the user's side, breaks these try-catch shenanigans + import('@react-email/render') + .then(({ render }) => { + resolve(render(node)); + }) + .catch(() => { + reject( + Error( + 'Failed to render React component. Make sure to install `@react-email/render`', + ), + ); + }); + }); +} From a4ab732790c1cf0e45255c209e5155b1611b2602 Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Thu, 11 Sep 2025 10:23:17 -0300 Subject: [PATCH 3/7] lint --- src/batch/batch.ts | 2 +- src/emails/emails.ts | 6 ++---- src/render.ts | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/batch/batch.ts b/src/batch/batch.ts index 848a7037..777f328c 100644 --- a/src/batch/batch.ts +++ b/src/batch/batch.ts @@ -1,5 +1,6 @@ import type { EmailApiOptions } from '../common/interfaces/email-api-options.interface'; import { parseEmailToApiOptions } from '../common/utils/parse-email-to-api-options'; +import { render } from '../render'; import type { Resend } from '../resend'; import type { CreateBatchOptions, @@ -7,7 +8,6 @@ import type { CreateBatchResponse, CreateBatchSuccessResponse, } from './interfaces/create-batch-options.interface'; -import { render } from '../render'; export class Batch { constructor(private readonly resend: Resend) {} diff --git a/src/emails/emails.ts b/src/emails/emails.ts index 311574d2..8be8b119 100644 --- a/src/emails/emails.ts +++ b/src/emails/emails.ts @@ -1,6 +1,7 @@ import type * as React from 'react'; import { buildPaginationQuery } from '../common/utils/build-pagination-query'; import { parseEmailToApiOptions } from '../common/utils/parse-email-to-api-options'; +import { render } from '../render'; import type { Resend } from '../resend'; import type { CancelEmailResponse, @@ -26,7 +27,6 @@ import type { UpdateEmailResponse, UpdateEmailResponseSuccess, } from './interfaces/update-email-options.interface'; -import { render } from '../render'; export class Emails { constructor(private readonly resend: Resend) {} @@ -43,9 +43,7 @@ export class Emails { options: CreateEmailRequestOptions = {}, ): Promise { if (payload.react) { - payload.html = await render( - payload.react as React.ReactElement, - ); + payload.html = await render(payload.react as React.ReactElement); } const data = await this.resend.post( diff --git a/src/render.ts b/src/render.ts index 7b80f16f..d4c30924 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,7 +1,7 @@ export function render(node: React.ReactNode) { return new Promise((resolve, reject) => { - // we don't use async here, because tsup transpiles it to - // using a generator syntax that, if used in conjunction + // we don't use async here, because tsup transpiles it to + // using a generator syntax that, if used in conjunction // with a bundler on the user's side, breaks these try-catch shenanigans import('@react-email/render') .then(({ render }) => { From 6d863e953082c7a0de217b2e8b35d935194775ba Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Thu, 11 Sep 2025 12:32:38 -0300 Subject: [PATCH 4/7] update broadcasts --- src/broadcasts/broadcasts.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/broadcasts/broadcasts.ts b/src/broadcasts/broadcasts.ts index 0b65eda2..4f15a4e0 100644 --- a/src/broadcasts/broadcasts.ts +++ b/src/broadcasts/broadcasts.ts @@ -28,9 +28,9 @@ import type { UpdateBroadcastResponse, UpdateBroadcastResponseSuccess, } from './interfaces/update-broadcast.interface'; +import { render } from '../render'; export class Broadcasts { - private renderAsync?: (component: React.ReactElement) => Promise; constructor(private readonly resend: Resend) {} async create( @@ -38,18 +38,7 @@ export class Broadcasts { options: CreateBroadcastRequestOptions = {}, ): Promise { if (payload.react) { - if (!this.renderAsync) { - try { - const { renderAsync } = await import('@react-email/render'); - this.renderAsync = renderAsync; - } catch { - throw new Error( - 'Failed to render React component. Make sure to install `@react-email/render`', - ); - } - } - - payload.html = await this.renderAsync( + payload.html = await render( payload.react as React.ReactElement, ); } From 188a0a393b6c8286cf9916854e91c5c8eebe6f13 Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Thu, 11 Sep 2025 12:34:34 -0300 Subject: [PATCH 5/7] lint --- src/broadcasts/broadcasts.ts | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/broadcasts/broadcasts.ts b/src/broadcasts/broadcasts.ts index 4f15a4e0..0e23c98a 100644 --- a/src/broadcasts/broadcasts.ts +++ b/src/broadcasts/broadcasts.ts @@ -1,5 +1,6 @@ import type * as React from 'react'; import { buildPaginationQuery } from '../common/utils/build-pagination-query'; +import { render } from '../render'; import type { Resend } from '../resend'; import type { CreateBroadcastOptions, @@ -28,19 +29,16 @@ import type { UpdateBroadcastResponse, UpdateBroadcastResponseSuccess, } from './interfaces/update-broadcast.interface'; -import { render } from '../render'; export class Broadcasts { - constructor(private readonly resend: Resend) {} + constructor(private readonly resend: Resend) { } async create( payload: CreateBroadcastOptions, options: CreateBroadcastRequestOptions = {}, ): Promise { if (payload.react) { - payload.html = await render( - payload.react as React.ReactElement, - ); + payload.html = await render(payload.react as React.ReactElement); } const data = await this.resend.post( @@ -102,20 +100,7 @@ export class Broadcasts { payload: UpdateBroadcastOptions, ): Promise { if (payload.react) { - if (!this.renderAsync) { - try { - const { renderAsync } = await import('@react-email/render'); - this.renderAsync = renderAsync; - } catch { - throw new Error( - 'Failed to render React component. Make sure to install `@react-email/render`', - ); - } - } - - payload.html = await this.renderAsync( - payload.react as React.ReactElement, - ); + payload.html = await render(payload.react); } const data = await this.resend.patch( From 0b29f9bd6969bf05c82374091d0418df4eefe732 Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Thu, 11 Sep 2025 12:37:02 -0300 Subject: [PATCH 6/7] remove extra type things --- src/broadcasts/broadcasts.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/broadcasts/broadcasts.ts b/src/broadcasts/broadcasts.ts index 0e23c98a..36944538 100644 --- a/src/broadcasts/broadcasts.ts +++ b/src/broadcasts/broadcasts.ts @@ -1,4 +1,3 @@ -import type * as React from 'react'; import { buildPaginationQuery } from '../common/utils/build-pagination-query'; import { render } from '../render'; import type { Resend } from '../resend'; @@ -38,7 +37,7 @@ export class Broadcasts { options: CreateBroadcastRequestOptions = {}, ): Promise { if (payload.react) { - payload.html = await render(payload.react as React.ReactElement); + payload.html = await render(payload.react); } const data = await this.resend.post( From 33e8be6d7e3013b628d1783f199c3bc32c9fcf76 Mon Sep 17 00:00:00 2001 From: gabriel miranda Date: Mon, 15 Sep 2025 14:24:40 -0300 Subject: [PATCH 7/7] lint --- src/broadcasts/broadcasts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/broadcasts/broadcasts.ts b/src/broadcasts/broadcasts.ts index 36944538..070d61a5 100644 --- a/src/broadcasts/broadcasts.ts +++ b/src/broadcasts/broadcasts.ts @@ -30,7 +30,7 @@ import type { } from './interfaces/update-broadcast.interface'; export class Broadcasts { - constructor(private readonly resend: Resend) { } + constructor(private readonly resend: Resend) {} async create( payload: CreateBroadcastOptions,