Last active
April 3, 2026 17:35
-
-
Save mortenson/4e7f3839f6a53814ad08cde382120962 to your computer and use it in GitHub Desktop.
Render all React Email (react-email) emails to dist
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { render, pretty, toPlainText } from "@react-email/render"; | |
| import React from "react"; | |
| import fs from "fs/promises"; | |
| import path from "path"; | |
| import { fileURLToPath } from 'url'; | |
| /* | |
| This script will take all emails from the `emails` directory and render them to dist. | |
| For example, given an email component `emails/welcome.tsx` with a single and default export, this would output: | |
| - dist/emails/welcome.html | |
| - dist/emails/welcome.txt | |
| This is especially useful if you don't want to run React on your server, and instead want to replace placeholders | |
| in the static output from this script. | |
| */ | |
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | |
| const dirPath = path.join(__dirname, './emails'); | |
| async function loadAllEmails(): Promise<Record<string, React.ComponentType>> { | |
| const files = await fs.readdir(dirPath); | |
| const modules: Record<string, React.ComponentType> = {}; | |
| for (const file of files) { | |
| const moduleName = path.parse(file).name; | |
| const fullPath = path.join(dirPath, file); | |
| const module = await import(`file://${fullPath}`); | |
| modules[moduleName] = module.default; | |
| } | |
| return modules; | |
| } | |
| const emails = await loadAllEmails() | |
| type RenderResult = { | |
| id: string; | |
| html: string; | |
| plain: string; | |
| }; | |
| const output: RenderResult[] = await Promise.all( | |
| Object.entries(emails).map(async ([id, component]) => { | |
| const html = await pretty(await render(React.createElement(component))); | |
| const plain = toPlainText(html); | |
| return { | |
| id, | |
| html, | |
| plain, | |
| }; | |
| }), | |
| ); | |
| await fs.mkdir("./dist/emails", { recursive: true }); | |
| await Promise.all( | |
| output.map(async (result) => { | |
| const p1 = fs.writeFile(`./dist/emails/${result.id}.html`, result.html); | |
| const p2 = fs.writeFile(`./dist/emails/${result.id}.txt`, result.plain); | |
| return Promise.all([p1, p2]); | |
| }), | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment