react-email 5.0.0-canary.5 → 5.0.0-canary.7
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 +4 -0
- package/dist/index.js +38 -14
- package/package.json +3 -2
- package/src/commands/build.ts +5 -5
- package/src/commands/dev.ts +1 -1
- package/src/commands/export.ts +5 -5
- package/src/commands/resend-setup.ts +22 -0
- package/src/index.ts +10 -0
- package/src/utils/__snapshots__/tree.spec.ts.snap +1 -0
- package/src/utils/conf.ts +9 -0
- package/src/utils/preview/get-env-variables-for-preview-app.ts +2 -0
- package/src/utils/preview/start-dev-server.ts +3 -1
- package/src/utils/style-text.ts +1 -1
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { parse } from "@babel/parser";
|
|
|
17
17
|
import traverseModule from "@babel/traverse";
|
|
18
18
|
import { createMatchPath, loadConfig } from "tsconfig-paths";
|
|
19
19
|
import http from "node:http";
|
|
20
|
+
import Conf from "conf";
|
|
20
21
|
import * as nodeUtil from "node:util";
|
|
21
22
|
import { lookup } from "mime-types";
|
|
22
23
|
import os from "node:os";
|
|
@@ -86,7 +87,7 @@ const getEmailsDirectoryMetadata = async (absolutePathToEmailsDirectory, keepFil
|
|
|
86
87
|
//#region package.json
|
|
87
88
|
var package_default = {
|
|
88
89
|
name: "react-email",
|
|
89
|
-
version: "5.0.0-canary.
|
|
90
|
+
version: "5.0.0-canary.7",
|
|
90
91
|
description: "A live preview of your emails right in your browser.",
|
|
91
92
|
bin: { "email": "./dist/index.js" },
|
|
92
93
|
type: "module",
|
|
@@ -110,6 +111,7 @@ var package_default = {
|
|
|
110
111
|
"@babel/traverse": "^7.27.0",
|
|
111
112
|
"chokidar": "^4.0.3",
|
|
112
113
|
"commander": "^13.0.0",
|
|
114
|
+
"conf": "^15.0.2",
|
|
113
115
|
"debounce": "^2.0.0",
|
|
114
116
|
"esbuild": "^0.25.0",
|
|
115
117
|
"glob": "^11.0.0",
|
|
@@ -242,10 +244,8 @@ module.exports = {
|
|
|
242
244
|
const getEmailSlugsFromEmailDirectory = (emailDirectory, emailsDirectoryAbsolutePath) => {
|
|
243
245
|
const directoryPathRelativeToEmailsDirectory = emailDirectory.absolutePath.replace(emailsDirectoryAbsolutePath, "").trim();
|
|
244
246
|
const slugs = [];
|
|
245
|
-
emailDirectory.emailFilenames
|
|
246
|
-
emailDirectory.subDirectories.
|
|
247
|
-
slugs.push(...getEmailSlugsFromEmailDirectory(directory, emailsDirectoryAbsolutePath));
|
|
248
|
-
});
|
|
247
|
+
for (const filename of emailDirectory.emailFilenames) slugs.push(path.join(directoryPathRelativeToEmailsDirectory, filename).split(path.sep).filter((segment) => segment.length > 0));
|
|
248
|
+
for (const directory of emailDirectory.subDirectories) slugs.push(...getEmailSlugsFromEmailDirectory(directory, emailsDirectoryAbsolutePath));
|
|
249
249
|
return slugs;
|
|
250
250
|
};
|
|
251
251
|
const forceSSGForEmailPreviews = async (emailsDirPath, builtPreviewAppPath) => {
|
|
@@ -587,18 +587,27 @@ const setupHotreloading = async (devServer$1, emailDirRelativePath) => {
|
|
|
587
587
|
return watcher;
|
|
588
588
|
};
|
|
589
589
|
|
|
590
|
+
//#endregion
|
|
591
|
+
//#region src/utils/conf.ts
|
|
592
|
+
const encryptionKey = "h2#x658}1#qY(@!:7,BD1J)q12$[tM25";
|
|
593
|
+
const conf = new Conf({
|
|
594
|
+
projectName: "react-email",
|
|
595
|
+
encryptionKey
|
|
596
|
+
});
|
|
597
|
+
|
|
590
598
|
//#endregion
|
|
591
599
|
//#region src/utils/style-text.ts
|
|
592
600
|
const styleText = nodeUtil.styleText ? nodeUtil.styleText : (_, text) => text;
|
|
593
601
|
|
|
594
602
|
//#endregion
|
|
595
603
|
//#region src/utils/preview/get-env-variables-for-preview-app.ts
|
|
596
|
-
const getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, previewServerLocation, cwd) => {
|
|
604
|
+
const getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, previewServerLocation, cwd, resendApiKey) => {
|
|
597
605
|
return {
|
|
598
606
|
EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
|
|
599
607
|
EMAILS_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEmailsDirectory),
|
|
600
608
|
PREVIEW_SERVER_LOCATION: previewServerLocation,
|
|
601
|
-
USER_PROJECT_LOCATION: cwd
|
|
609
|
+
USER_PROJECT_LOCATION: cwd,
|
|
610
|
+
RESEND_API_KEY: resendApiKey
|
|
602
611
|
};
|
|
603
612
|
};
|
|
604
613
|
|
|
@@ -648,7 +657,7 @@ const safeAsyncServerListen = (server, port) => {
|
|
|
648
657
|
};
|
|
649
658
|
const startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
|
|
650
659
|
const [majorNodeVersion] = process.versions.node.split(".");
|
|
651
|
-
if (majorNodeVersion && Number.parseInt(majorNodeVersion) < 20) {
|
|
660
|
+
if (majorNodeVersion && Number.parseInt(majorNodeVersion, 10) < 20) {
|
|
652
661
|
console.error(` ${logSymbols.error} Node ${majorNodeVersion} is not supported. Please upgrade to Node 20 or higher.`);
|
|
653
662
|
process.exit(1);
|
|
654
663
|
}
|
|
@@ -701,7 +710,7 @@ const startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath,
|
|
|
701
710
|
process.env = {
|
|
702
711
|
NODE_ENV: "development",
|
|
703
712
|
...process.env,
|
|
704
|
-
...getEnvVariablesForPreviewApp(path.normalize(emailsDirRelativePath), previewServerLocation, process.cwd())
|
|
713
|
+
...getEnvVariablesForPreviewApp(path.normalize(emailsDirRelativePath), previewServerLocation, process.cwd(), conf.get("resendApiKey"))
|
|
705
714
|
};
|
|
706
715
|
const app = (await previewServer.import("next", { default: true }))({
|
|
707
716
|
dev: false,
|
|
@@ -803,7 +812,7 @@ const dev = async ({ dir: emailsDirRelativePath, port }) => {
|
|
|
803
812
|
console.error(`Missing ${emailsDirRelativePath} folder`);
|
|
804
813
|
process.exit(1);
|
|
805
814
|
}
|
|
806
|
-
await setupHotreloading(await startDevServer(emailsDirRelativePath, emailsDirRelativePath, Number.parseInt(port)), emailsDirRelativePath);
|
|
815
|
+
await setupHotreloading(await startDevServer(emailsDirRelativePath, emailsDirRelativePath, Number.parseInt(port, 10)), emailsDirRelativePath);
|
|
807
816
|
} catch (error) {
|
|
808
817
|
console.log(error);
|
|
809
818
|
process.exit(1);
|
|
@@ -861,10 +870,8 @@ const renderingUtilitiesExporter = (emailTemplates) => ({
|
|
|
861
870
|
//#region src/commands/export.ts
|
|
862
871
|
const getEmailTemplatesFromDirectory = (emailDirectory) => {
|
|
863
872
|
const templatePaths = [];
|
|
864
|
-
emailDirectory.emailFilenames
|
|
865
|
-
emailDirectory.subDirectories.
|
|
866
|
-
templatePaths.push(...getEmailTemplatesFromDirectory(directory));
|
|
867
|
-
});
|
|
873
|
+
for (const filename of emailDirectory.emailFilenames) templatePaths.push(path.join(emailDirectory.absolutePath, filename));
|
|
874
|
+
for (const directory of emailDirectory.subDirectories) templatePaths.push(...getEmailTemplatesFromDirectory(directory));
|
|
868
875
|
return templatePaths;
|
|
869
876
|
};
|
|
870
877
|
const require = createRequire(url.fileURLToPath(import.meta.url));
|
|
@@ -959,6 +966,22 @@ const exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirec
|
|
|
959
966
|
}
|
|
960
967
|
};
|
|
961
968
|
|
|
969
|
+
//#endregion
|
|
970
|
+
//#region src/commands/resend-setup.ts
|
|
971
|
+
async function resendSetup(apiKey) {
|
|
972
|
+
const previousValue = conf.get("resendApiKey");
|
|
973
|
+
if (typeof previousValue === "string" && previousValue.length > 0) {
|
|
974
|
+
if (!(await prompts({
|
|
975
|
+
type: "confirm",
|
|
976
|
+
name: "replaceApiKey",
|
|
977
|
+
message: `You already have a Resend API Key configured (${styleText("grey", previousValue.slice(0, 11))}...). Do you want to replace it?`,
|
|
978
|
+
initial: false
|
|
979
|
+
})).replaceApiKey) process.exit(0);
|
|
980
|
+
}
|
|
981
|
+
conf.set("resendApiKey", apiKey);
|
|
982
|
+
console.info(`${logSymbols.success} Resend integration successfully set up`);
|
|
983
|
+
}
|
|
984
|
+
|
|
962
985
|
//#endregion
|
|
963
986
|
//#region src/commands/start.ts
|
|
964
987
|
const start = async () => {
|
|
@@ -1001,6 +1024,7 @@ program.command("export").description("Build the templates to the `out` director
|
|
|
1001
1024
|
plainText,
|
|
1002
1025
|
pretty
|
|
1003
1026
|
}));
|
|
1027
|
+
program.command("resend").command("setup").description("Sets up the integration between the React Email CLI, and your Resend account through an API Key").argument("apiKey", "API Key for use setting up the integration").action(resendSetup);
|
|
1004
1028
|
program.parse();
|
|
1005
1029
|
|
|
1006
1030
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-email",
|
|
3
|
-
"version": "5.0.0-canary.
|
|
3
|
+
"version": "5.0.0-canary.7",
|
|
4
4
|
"description": "A live preview of your emails right in your browser.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"email": "./dist/index.js"
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"@babel/traverse": "^7.27.0",
|
|
25
25
|
"chokidar": "^4.0.3",
|
|
26
26
|
"commander": "^13.0.0",
|
|
27
|
+
"conf": "^15.0.2",
|
|
27
28
|
"debounce": "^2.0.0",
|
|
28
29
|
"esbuild": "^0.25.0",
|
|
29
30
|
"glob": "^11.0.0",
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"react": "19.0.0",
|
|
47
48
|
"react-dom": "19.0.0",
|
|
48
49
|
"typescript": "5.8.3",
|
|
49
|
-
"@react-email/components": "1.0.0-canary.
|
|
50
|
+
"@react-email/components": "1.0.0-canary.7"
|
|
50
51
|
},
|
|
51
52
|
"scripts": {
|
|
52
53
|
"build": "tsdown",
|
package/src/commands/build.ts
CHANGED
|
@@ -115,23 +115,23 @@ const getEmailSlugsFromEmailDirectory = (
|
|
|
115
115
|
.trim();
|
|
116
116
|
|
|
117
117
|
const slugs = [] as Array<string>[];
|
|
118
|
-
emailDirectory.emailFilenames
|
|
118
|
+
for (const filename of emailDirectory.emailFilenames) {
|
|
119
119
|
slugs.push(
|
|
120
120
|
path
|
|
121
121
|
.join(directoryPathRelativeToEmailsDirectory, filename)
|
|
122
122
|
.split(path.sep)
|
|
123
123
|
// sometimes it gets empty segments due to trailing slashes
|
|
124
124
|
.filter((segment) => segment.length > 0),
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
emailDirectory.subDirectories
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
for (const directory of emailDirectory.subDirectories) {
|
|
128
128
|
slugs.push(
|
|
129
129
|
...getEmailSlugsFromEmailDirectory(
|
|
130
130
|
directory,
|
|
131
131
|
emailsDirectoryAbsolutePath,
|
|
132
132
|
),
|
|
133
133
|
);
|
|
134
|
-
}
|
|
134
|
+
}
|
|
135
135
|
|
|
136
136
|
return slugs;
|
|
137
137
|
};
|
package/src/commands/dev.ts
CHANGED
|
@@ -16,7 +16,7 @@ export const dev = async ({ dir: emailsDirRelativePath, port }: Args) => {
|
|
|
16
16
|
const devServer = await startDevServer(
|
|
17
17
|
emailsDirRelativePath,
|
|
18
18
|
emailsDirRelativePath, // defaults to ./emails/static for the static files that are served to the preview
|
|
19
|
-
Number.parseInt(port),
|
|
19
|
+
Number.parseInt(port, 10),
|
|
20
20
|
);
|
|
21
21
|
|
|
22
22
|
await setupHotreloading(devServer, emailsDirRelativePath);
|
package/src/commands/export.ts
CHANGED
|
@@ -19,12 +19,12 @@ import { registerSpinnerAutostopping } from '../utils/register-spinner-autostopp
|
|
|
19
19
|
|
|
20
20
|
const getEmailTemplatesFromDirectory = (emailDirectory: EmailsDirectory) => {
|
|
21
21
|
const templatePaths = [] as string[];
|
|
22
|
-
emailDirectory.emailFilenames
|
|
23
|
-
templatePaths.push(path.join(emailDirectory.absolutePath, filename))
|
|
24
|
-
|
|
25
|
-
emailDirectory.subDirectories
|
|
22
|
+
for (const filename of emailDirectory.emailFilenames) {
|
|
23
|
+
templatePaths.push(path.join(emailDirectory.absolutePath, filename));
|
|
24
|
+
}
|
|
25
|
+
for (const directory of emailDirectory.subDirectories) {
|
|
26
26
|
templatePaths.push(...getEmailTemplatesFromDirectory(directory));
|
|
27
|
-
}
|
|
27
|
+
}
|
|
28
28
|
|
|
29
29
|
return templatePaths;
|
|
30
30
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import logSymbols from 'log-symbols';
|
|
2
|
+
import prompts from 'prompts';
|
|
3
|
+
import { conf } from '../utils/conf.js';
|
|
4
|
+
import { styleText } from '../utils/style-text.js';
|
|
5
|
+
|
|
6
|
+
export async function resendSetup(apiKey: string) {
|
|
7
|
+
const previousValue = conf.get('resendApiKey');
|
|
8
|
+
if (typeof previousValue === 'string' && previousValue.length > 0) {
|
|
9
|
+
const response = await prompts({
|
|
10
|
+
type: 'confirm',
|
|
11
|
+
name: 'replaceApiKey',
|
|
12
|
+
message: `You already have a Resend API Key configured (${styleText('grey', previousValue.slice(0, 11))}...). Do you want to replace it?`,
|
|
13
|
+
initial: false,
|
|
14
|
+
});
|
|
15
|
+
if (!response.replaceApiKey) {
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
conf.set('resendApiKey', apiKey);
|
|
21
|
+
console.info(`${logSymbols.success} Resend integration successfully set up`);
|
|
22
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { program } from 'commander';
|
|
|
3
3
|
import { build } from './commands/build.js';
|
|
4
4
|
import { dev } from './commands/dev.js';
|
|
5
5
|
import { exportTemplates } from './commands/export.js';
|
|
6
|
+
import { resendSetup } from './commands/resend-setup.js';
|
|
6
7
|
import { start } from './commands/start.js';
|
|
7
8
|
import { packageJson } from './utils/packageJson.js';
|
|
8
9
|
|
|
@@ -52,4 +53,13 @@ program
|
|
|
52
53
|
exportTemplates(outDir, srcDir, { silent, plainText, pretty }),
|
|
53
54
|
);
|
|
54
55
|
|
|
56
|
+
program
|
|
57
|
+
.command('resend')
|
|
58
|
+
.command('setup')
|
|
59
|
+
.description(
|
|
60
|
+
'Sets up the integration between the React Email CLI, and your Resend account through an API Key',
|
|
61
|
+
)
|
|
62
|
+
.argument('apiKey', 'API Key for use setting up the integration')
|
|
63
|
+
.action(resendSetup);
|
|
64
|
+
|
|
55
65
|
program.parse();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
|
|
3
|
+
// Just simple encryption. This isn't completely safe
|
|
4
|
+
// because anyone can find this key here
|
|
5
|
+
const encryptionKey = 'h2#x658}1#qY(@!:7,BD1J)q12$[tM25';
|
|
6
|
+
|
|
7
|
+
export const conf = new Conf<{
|
|
8
|
+
resendApiKey?: string;
|
|
9
|
+
}>({ projectName: 'react-email', encryptionKey });
|
|
@@ -4,11 +4,13 @@ export const getEnvVariablesForPreviewApp = (
|
|
|
4
4
|
relativePathToEmailsDirectory: string,
|
|
5
5
|
previewServerLocation: string,
|
|
6
6
|
cwd: string,
|
|
7
|
+
resendApiKey?: string,
|
|
7
8
|
) => {
|
|
8
9
|
return {
|
|
9
10
|
EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
|
|
10
11
|
EMAILS_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEmailsDirectory),
|
|
11
12
|
PREVIEW_SERVER_LOCATION: previewServerLocation,
|
|
12
13
|
USER_PROJECT_LOCATION: cwd,
|
|
14
|
+
RESEND_API_KEY: resendApiKey,
|
|
13
15
|
} as const;
|
|
14
16
|
};
|
|
@@ -5,6 +5,7 @@ import { createJiti } from 'jiti';
|
|
|
5
5
|
import logSymbols from 'log-symbols';
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
import { registerSpinnerAutostopping } from '../../utils/register-spinner-autostopping.js';
|
|
8
|
+
import { conf } from '../conf.js';
|
|
8
9
|
import { getPreviewServerLocation } from '../get-preview-server-location.js';
|
|
9
10
|
import { packageJson } from '../packageJson.js';
|
|
10
11
|
import { styleText } from '../style-text.js';
|
|
@@ -33,7 +34,7 @@ export const startDevServer = async (
|
|
|
33
34
|
port: number,
|
|
34
35
|
): Promise<http.Server> => {
|
|
35
36
|
const [majorNodeVersion] = process.versions.node.split('.');
|
|
36
|
-
if (majorNodeVersion && Number.parseInt(majorNodeVersion) < 20) {
|
|
37
|
+
if (majorNodeVersion && Number.parseInt(majorNodeVersion, 10) < 20) {
|
|
37
38
|
console.error(
|
|
38
39
|
` ${logSymbols.error} Node ${majorNodeVersion} is not supported. Please upgrade to Node 20 or higher.`,
|
|
39
40
|
);
|
|
@@ -131,6 +132,7 @@ export const startDevServer = async (
|
|
|
131
132
|
path.normalize(emailsDirRelativePath),
|
|
132
133
|
previewServerLocation,
|
|
133
134
|
process.cwd(),
|
|
135
|
+
conf.get('resendApiKey'),
|
|
134
136
|
),
|
|
135
137
|
};
|
|
136
138
|
|
package/src/utils/style-text.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as nodeUtil from 'node:util';
|
|
6
6
|
|
|
7
|
-
type StyleTextFunction =
|
|
7
|
+
type StyleTextFunction = typeof nodeUtil.styleText;
|
|
8
8
|
|
|
9
9
|
export const styleText: StyleTextFunction = (nodeUtil as any).styleText
|
|
10
10
|
? (nodeUtil as any).styleText
|