react-email 6.1.4 → 6.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/cli/index.mjs +91 -32
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# react-email
|
|
2
2
|
|
|
3
|
+
## 6.1.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1a61cb0: Avoid OOM when running `email export` on projects with many templates. esbuild builds now run in batches of 10 entry points, and the render phase runs each batch of 25 templates inside a `worker_threads` worker so V8 isolate memory is reclaimed between batches.
|
|
8
|
+
|
|
3
9
|
## 6.1.4
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/cli/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { Option, program } from "commander";
|
|
5
5
|
import * as fs$1 from "node:fs";
|
|
6
|
-
import fs, { existsSync, promises, statSync
|
|
6
|
+
import fs, { existsSync, promises, statSync } from "node:fs";
|
|
7
7
|
import * as path$2 from "node:path";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import url, { fileURLToPath } from "node:url";
|
|
@@ -31,7 +31,8 @@ import os from "node:os";
|
|
|
31
31
|
import Conf from "conf";
|
|
32
32
|
import * as nodeUtil from "node:util";
|
|
33
33
|
import { lookup } from "mime-types";
|
|
34
|
-
import {
|
|
34
|
+
import { Worker } from "node:worker_threads";
|
|
35
|
+
import { build, stop } from "esbuild";
|
|
35
36
|
import { glob } from "glob";
|
|
36
37
|
import normalize$1 from "normalize-path";
|
|
37
38
|
//#region \0rolldown/runtime.js
|
|
@@ -6522,7 +6523,7 @@ const getEmailsDirectoryMetadata = async (absolutePathToEmailsDirectory, keepFil
|
|
|
6522
6523
|
//#region package.json
|
|
6523
6524
|
var package_default = {
|
|
6524
6525
|
name: "react-email",
|
|
6525
|
-
version: "6.1.
|
|
6526
|
+
version: "6.1.5",
|
|
6526
6527
|
description: "A live preview of your emails right in your browser.",
|
|
6527
6528
|
bin: { "email": "./dist/cli/index.mjs" },
|
|
6528
6529
|
type: "module",
|
|
@@ -7403,7 +7404,40 @@ const getEmailTemplatesFromDirectory = (emailDirectory) => {
|
|
|
7403
7404
|
for (const directory of emailDirectory.subDirectories) templatePaths.push(...getEmailTemplatesFromDirectory(directory));
|
|
7404
7405
|
return templatePaths;
|
|
7405
7406
|
};
|
|
7406
|
-
const
|
|
7407
|
+
const BUILD_BATCH_SIZE = 10;
|
|
7408
|
+
const RENDER_BATCH_SIZE = 25;
|
|
7409
|
+
const renderWorkerSource = `
|
|
7410
|
+
const { unlinkSync, writeFileSync } = require('node:fs');
|
|
7411
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
7412
|
+
|
|
7413
|
+
const { templates, options } = workerData;
|
|
7414
|
+
|
|
7415
|
+
(async () => {
|
|
7416
|
+
for (const template of templates) {
|
|
7417
|
+
try {
|
|
7418
|
+
const emailModule = require(template);
|
|
7419
|
+
const rendered = await emailModule.render(
|
|
7420
|
+
emailModule.reactEmailCreateReactElement(emailModule.default, {}),
|
|
7421
|
+
options,
|
|
7422
|
+
);
|
|
7423
|
+
const htmlPath = template.replace(
|
|
7424
|
+
'.cjs',
|
|
7425
|
+
options.plainText ? '.txt' : '.html',
|
|
7426
|
+
);
|
|
7427
|
+
writeFileSync(htmlPath, rendered);
|
|
7428
|
+
unlinkSync(template);
|
|
7429
|
+
parentPort.postMessage({ type: 'progress', template });
|
|
7430
|
+
} catch (exception) {
|
|
7431
|
+
parentPort.postMessage({
|
|
7432
|
+
type: 'error',
|
|
7433
|
+
template,
|
|
7434
|
+
message: exception && exception.stack ? exception.stack : String(exception),
|
|
7435
|
+
});
|
|
7436
|
+
process.exit(1);
|
|
7437
|
+
}
|
|
7438
|
+
}
|
|
7439
|
+
})();
|
|
7440
|
+
`;
|
|
7407
7441
|
const exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirectoryPath, options) => {
|
|
7408
7442
|
let spinner;
|
|
7409
7443
|
if (!options.silent) {
|
|
@@ -7423,20 +7457,24 @@ const exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirec
|
|
|
7423
7457
|
if (fs.existsSync(pathToWhereEmailMarkupShouldBeDumped)) fs.rmSync(pathToWhereEmailMarkupShouldBeDumped, { recursive: true });
|
|
7424
7458
|
const allTemplates = getEmailTemplatesFromDirectory(emailsDirectoryMetadata);
|
|
7425
7459
|
try {
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7460
|
+
for (let i = 0; i < allTemplates.length; i += BUILD_BATCH_SIZE) {
|
|
7461
|
+
const batch = allTemplates.slice(i, i + BUILD_BATCH_SIZE);
|
|
7462
|
+
await build({
|
|
7463
|
+
bundle: true,
|
|
7464
|
+
entryPoints: batch,
|
|
7465
|
+
external: ["css-tree"],
|
|
7466
|
+
format: "cjs",
|
|
7467
|
+
jsx: "automatic",
|
|
7468
|
+
loader: { ".js": "jsx" },
|
|
7469
|
+
logLevel: "silent",
|
|
7470
|
+
outExtension: { ".js": ".cjs" },
|
|
7471
|
+
outdir: pathToWhereEmailMarkupShouldBeDumped,
|
|
7472
|
+
platform: "node",
|
|
7473
|
+
plugins: [renderingUtilitiesExporter(batch)],
|
|
7474
|
+
write: true
|
|
7475
|
+
});
|
|
7476
|
+
await stop();
|
|
7477
|
+
}
|
|
7440
7478
|
} catch (exception) {
|
|
7441
7479
|
if (spinner) stopSpinnerAndPersist(spinner, {
|
|
7442
7480
|
symbol: logSymbols.error,
|
|
@@ -7451,20 +7489,41 @@ const exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirec
|
|
|
7451
7489
|
spinner.setText(`rendering ${allBuiltTemplates[0]?.split("/").pop()}`);
|
|
7452
7490
|
spinner.start();
|
|
7453
7491
|
}
|
|
7454
|
-
for
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7492
|
+
for (let i = 0; i < allBuiltTemplates.length; i += RENDER_BATCH_SIZE) {
|
|
7493
|
+
const batch = allBuiltTemplates.slice(i, i + RENDER_BATCH_SIZE);
|
|
7494
|
+
let failedTemplate;
|
|
7495
|
+
let failureMessage;
|
|
7496
|
+
try {
|
|
7497
|
+
await new Promise((resolve, reject) => {
|
|
7498
|
+
const worker = new Worker(renderWorkerSource, {
|
|
7499
|
+
eval: true,
|
|
7500
|
+
workerData: {
|
|
7501
|
+
templates: batch,
|
|
7502
|
+
options
|
|
7503
|
+
}
|
|
7504
|
+
});
|
|
7505
|
+
worker.on("message", (msg) => {
|
|
7506
|
+
if (msg.type === "progress") {
|
|
7507
|
+
if (spinner) spinner.setText(`rendering ${msg.template.split("/").pop()}`);
|
|
7508
|
+
} else if (msg.type === "error") {
|
|
7509
|
+
failedTemplate = msg.template;
|
|
7510
|
+
failureMessage = msg.message;
|
|
7511
|
+
}
|
|
7512
|
+
});
|
|
7513
|
+
worker.on("error", reject);
|
|
7514
|
+
worker.on("exit", (code) => {
|
|
7515
|
+
if (code !== 0) reject(new Error(failureMessage ?? `Render worker exited with code ${code}`));
|
|
7516
|
+
else resolve();
|
|
7517
|
+
});
|
|
7518
|
+
});
|
|
7519
|
+
} catch (exception) {
|
|
7520
|
+
if (spinner) stopSpinnerAndPersist(spinner, {
|
|
7521
|
+
symbol: logSymbols.error,
|
|
7522
|
+
text: failedTemplate ? `failed when rendering ${failedTemplate.split("/").pop()}` : "failed when rendering"
|
|
7523
|
+
});
|
|
7524
|
+
console.error(exception);
|
|
7525
|
+
process.exit(1);
|
|
7526
|
+
}
|
|
7468
7527
|
}
|
|
7469
7528
|
if (spinner) {
|
|
7470
7529
|
spinner.succeed("Rendered all files");
|