Skip to content

Commit 7ac7a66

Browse files
committed
fixup! Upgrade to Next.js@15 and React@19
1 parent f74a142 commit 7ac7a66

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

src/emails/react-dom-server.edge.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
// This is needed because `renderEmail.ts` needs to import from server.edge
5+
// This is needed because `StorybookEmailRenderer.tsx` needs to import from server.edge
66
// directly — see the comment in that file.
77
declare module "react-dom/server.edge" {
88
export * from "react-dom/server";

src/emails/renderEmail.ts

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,46 @@
44

55
import "../app/functions/server/notInClientComponent";
66
import mjml2html from "mjml";
7+
import { Transform } from "node:stream";
78
import { ReactNode } from "react";
89

910
export async function renderEmail(emailTemplate: ReactNode): Promise<string> {
11+
return mjml2html(await renderToString(emailTemplate), {
12+
validationLevel: "strict",
13+
beautify: false,
14+
minify: false,
15+
ignoreIncludes: true,
16+
}).html;
17+
}
18+
19+
async function renderToString(node: ReactNode): Promise<string> {
1020
// Importing react-dom/server dynamically here is a workaround for the following error:
1121
//
1222
// Error: react-dom/server is not supported in React Server Components.
1323
//
14-
// It's a bit of a pain though, as it's the only reason this needs to be an
15-
// async function.
1624
// https://github.com/vercel/next.js/issues/43810#issuecomment-2437931415
25+
const { renderToPipeableStream } = await import("react-dom/server");
26+
// It looks like we can't use `renderToStaticMarkup`, as that results in the following error:
1727
//
18-
// Also, react-dom/server.edge is apparently needed instead of react-dom/server
19-
// to avoid this error:
28+
// Internal Error: do not use legacy react-dom/server APIs. If you encountered this error, please open an issue on the Next.js repo.
2029
//
21-
// Uncaught ReferenceError: MessageChannel is not defined
22-
//
23-
// See https://github.com/facebook/react/issues/31827#issuecomment-2563094822
24-
const { renderToStaticMarkup } = await import("react-dom/server.edge");
25-
return mjml2html(renderToStaticMarkup(emailTemplate), {
26-
validationLevel: "strict",
27-
beautify: false,
28-
minify: false,
29-
ignoreIncludes: true,
30-
}).html;
30+
// Hence this `renderToPipeableStream` mess.
31+
const { pipe } = renderToPipeableStream(node);
32+
return new Promise((resolve, reject) => {
33+
const parts: string[] = [];
34+
// It's not clear to me if there's a better to `pipe` a rendered `node` to a string,
35+
// but this works and at this point I'm fed up, so leaving it at this.
36+
// Feel free to replace by a better way.
37+
const transformer = new Transform({
38+
transform: (chunk, encoding, callback) => {
39+
callback(null, chunk.toString());
40+
},
41+
});
42+
transformer.on("data", (part) => parts.push(part));
43+
transformer.on("error", reject);
44+
transformer.on("end", () => {
45+
return resolve(parts.join(""));
46+
});
47+
pipe(transformer);
48+
});
3149
}

0 commit comments

Comments
 (0)