react-email 4.0.8 → 4.0.9
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 +14 -0
- package/dist/cli/index.mjs +205 -180
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/app-build-manifest.json +14 -14
- package/dist/preview/.next/build-manifest.json +2 -2
- package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/preview/.next/next-server.js.nft.json +1 -1
- package/dist/preview/.next/prerender-manifest.json +3 -3
- package/dist/preview/.next/server/app/_not-found/page.js +1 -1
- package/dist/preview/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/page.js +1 -1
- package/dist/preview/.next/server/app/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page.js +137 -75
- package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/chunks/267.js +14 -0
- package/dist/preview/.next/server/chunks/346.js +1 -0
- package/dist/preview/.next/server/chunks/{886.js → 775.js} +3 -3
- package/dist/preview/.next/server/pages/500.html +1 -1
- package/dist/preview/.next/server/server-reference-manifest.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.json +1 -1
- package/dist/preview/.next/static/chunks/33-ff3f70a80570ecda.js +1 -0
- package/dist/preview/.next/static/chunks/416-9c899340cfaa07d4.js +1 -0
- package/dist/preview/.next/static/chunks/516-2716d86d2f8b9000.js +1 -0
- package/dist/preview/.next/static/chunks/{587-2b8de61789f0fd1b.js → 587-0644242ce9489212.js} +1 -1
- package/dist/preview/.next/static/chunks/app/{layout-a3d4e7b4de277118.js → layout-2726a60e293495d3.js} +1 -1
- package/dist/preview/.next/static/chunks/app/{page-0ee3a37f3a3f6f17.js → page-1d98e2313c60dd77.js} +1 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-c77ff9f2bb1709b3.js +1 -0
- package/dist/preview/.next/static/chunks/f33a14d2-a04f3be0523bd1fa.js +6 -0
- package/dist/preview/.next/static/css/6f42d128f111d7fa.css +3 -0
- package/dist/preview/.next/trace +27 -27
- package/package.json +44 -46
- package/src/actions/email-validation/check-compatibility.ts +1 -1
- package/src/actions/email-validation/check-images.spec.tsx +1 -1
- package/src/actions/email-validation/check-links.spec.tsx +1 -1
- package/src/actions/email-validation/quick-fetch.ts +1 -1
- package/src/actions/render-email-by-path.tsx +6 -6
- package/src/app/preview/[...slug]/preview.tsx +1 -1
- package/src/components/toolbar.tsx +1 -0
- package/src/contexts/emails.tsx +1 -3
- package/src/contexts/fragment-identifier.tsx +3 -1
- package/src/contexts/preview.tsx +1 -3
- package/src/hooks/use-email-rendering-result.ts +18 -5
- package/src/hooks/use-hot-reload.ts +1 -1
- package/src/utils/__snapshots__/get-email-component.spec.ts.snap +1 -1
- package/src/utils/caniemail/ast/get-object-variables.ts +1 -1
- package/src/utils/caniemail/tailwind/generate-tailwind-rules.ts +1 -1
- package/src/utils/caniemail/tailwind/get-tailwind-config.ts +1 -1
- package/src/utils/caniemail/tailwind/get-tailwind-metadata.ts +1 -1
- package/src/utils/contains-email-template.spec.ts +107 -0
- package/src/utils/contains-email-template.ts +33 -0
- package/src/utils/get-email-component.ts +16 -1
- package/src/utils/get-emails-directory-metadata.ts +24 -13
- package/src/utils/index.ts +2 -2
- package/src/utils/run-bundled-code.ts +1 -1
- package/tailwind.config.ts +2 -1
- package/tsconfig.json +1 -1
- package/dist/cli/index.d.mts +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -1320
- package/dist/index.js +0 -1234
- package/dist/preview/.next/server/chunks/265.js +0 -1
- package/dist/preview/.next/server/chunks/840.js +0 -14
- package/dist/preview/.next/static/chunks/246-e7336e2929971f63.js +0 -1
- package/dist/preview/.next/static/chunks/539-6e9405ecdc007bb7.js +0 -1
- package/dist/preview/.next/static/chunks/853-a01d49f63a859f3d.js +0 -1
- package/dist/preview/.next/static/chunks/afa401a5-55858bf5265319eb.js +0 -6
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-cab7e5e69e3b91e2.js +0 -1
- package/dist/preview/.next/static/css/67e57230289273a9.css +0 -3
- /package/dist/preview/.next/static/{t22IN7aANTezJAJOfFnv- → 3apYH6rky7aNn7g4RIJp5}/_buildManifest.js +0 -0
- /package/dist/preview/.next/static/{t22IN7aANTezJAJOfFnv- → 3apYH6rky7aNn7g4RIJp5}/_ssgManifest.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# react-email
|
|
2
2
|
|
|
3
|
+
## 4.0.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 643d841: Add .json import support for hot reloading
|
|
8
|
+
- f21a983: fix Node 18 support
|
|
9
|
+
- cd02449: Ensure dependencies outside emails directory are completely resolved
|
|
10
|
+
- 73a31ed: Fix dependent of dependents not causing hot reloads
|
|
11
|
+
- bdffd8c: fix backwards compatibility with `render` versions
|
|
12
|
+
- e7fa043: Fix access to files outside `static` directory
|
|
13
|
+
- 9aa033c: Use range of versions for dependencies
|
|
14
|
+
- ab70556: Fix non-email files being rendered during hot reloading
|
|
15
|
+
- 9c9aa5d: Add error message for when an email template does not have a default export
|
|
16
|
+
|
|
3
17
|
## 4.0.8
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/cli/index.mjs
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
3
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
4
|
}) : x)(function(x) {
|
|
5
|
-
if (typeof require !== "undefined")
|
|
6
|
-
return require.apply(this, arguments);
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
6
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
7
|
});
|
|
9
8
|
|
|
@@ -13,10 +12,10 @@ import { program } from "commander";
|
|
|
13
12
|
// package.json
|
|
14
13
|
var package_default = {
|
|
15
14
|
name: "react-email",
|
|
16
|
-
version: "4.0.
|
|
15
|
+
version: "4.0.9",
|
|
17
16
|
description: "A live preview of your emails right in your browser.",
|
|
18
17
|
bin: {
|
|
19
|
-
email: "./dist/cli/index.
|
|
18
|
+
email: "./dist/cli/index.mjs"
|
|
20
19
|
},
|
|
21
20
|
scripts: {
|
|
22
21
|
build: "tsup-node && node ./scripts/build-preview-server.mjs && pnpm install --frozen-lockfile",
|
|
@@ -33,75 +32,76 @@ var package_default = {
|
|
|
33
32
|
url: "https://github.com/resend/react-email.git",
|
|
34
33
|
directory: "packages/react-email"
|
|
35
34
|
},
|
|
36
|
-
keywords: [
|
|
35
|
+
keywords: [
|
|
36
|
+
"react",
|
|
37
|
+
"email"
|
|
38
|
+
],
|
|
37
39
|
engines: {
|
|
38
40
|
node: ">=18.0.0"
|
|
39
41
|
},
|
|
40
42
|
dependencies: {
|
|
41
|
-
"@babel/parser": "7.
|
|
42
|
-
"@babel/traverse": "7.
|
|
43
|
-
chalk: "
|
|
44
|
-
chokidar: "4.0.3",
|
|
45
|
-
commander: "
|
|
46
|
-
debounce: "2.0.0",
|
|
47
|
-
esbuild: "0.25.0",
|
|
48
|
-
glob: "
|
|
49
|
-
"log-symbols": "
|
|
50
|
-
"mime-types": "
|
|
51
|
-
next: "15.2.4",
|
|
52
|
-
"normalize-path": "3.0.0",
|
|
53
|
-
ora: "
|
|
54
|
-
"socket.io": "4.8.1"
|
|
43
|
+
"@babel/parser": "^7.27.0",
|
|
44
|
+
"@babel/traverse": "^7.27.0",
|
|
45
|
+
chalk: "^5.0.0",
|
|
46
|
+
chokidar: "^4.0.3",
|
|
47
|
+
commander: "^13.0.0",
|
|
48
|
+
debounce: "^2.0.0",
|
|
49
|
+
esbuild: "^0.25.0",
|
|
50
|
+
glob: "^11.0.0",
|
|
51
|
+
"log-symbols": "^7.0.0",
|
|
52
|
+
"mime-types": "^3.0.0",
|
|
53
|
+
next: "^15.2.4",
|
|
54
|
+
"normalize-path": "^3.0.0",
|
|
55
|
+
ora: "^8.0.0",
|
|
56
|
+
"socket.io": "^4.8.1"
|
|
55
57
|
},
|
|
56
58
|
devDependencies: {
|
|
57
59
|
"@babel/core": "7.26.10",
|
|
58
|
-
"@lottiefiles/dotlottie-react": "0.
|
|
59
|
-
"@radix-ui/colors": "
|
|
60
|
-
"@radix-ui/react-collapsible": "1.1.
|
|
61
|
-
"@radix-ui/react-dropdown-menu": "2.1.
|
|
62
|
-
"@radix-ui/react-popover": "1.1.
|
|
63
|
-
"@radix-ui/react-slot": "1.
|
|
64
|
-
"@radix-ui/react-tabs": "1.1.
|
|
65
|
-
"@radix-ui/react-toggle-group": "1.1.
|
|
66
|
-
"@radix-ui/react-tooltip": "1.
|
|
60
|
+
"@lottiefiles/dotlottie-react": "0.13.3",
|
|
61
|
+
"@radix-ui/colors": "3.0.0",
|
|
62
|
+
"@radix-ui/react-collapsible": "1.1.7",
|
|
63
|
+
"@radix-ui/react-dropdown-menu": "2.1.10",
|
|
64
|
+
"@radix-ui/react-popover": "1.1.10",
|
|
65
|
+
"@radix-ui/react-slot": "1.2.0",
|
|
66
|
+
"@radix-ui/react-tabs": "1.1.7",
|
|
67
|
+
"@radix-ui/react-toggle-group": "1.1.6",
|
|
68
|
+
"@radix-ui/react-tooltip": "1.2.3",
|
|
67
69
|
"@react-email/components": "workspace:*",
|
|
68
|
-
"@swc/core": "1.
|
|
70
|
+
"@swc/core": "1.11.21",
|
|
69
71
|
"@types/babel__core": "7.20.5",
|
|
70
|
-
"@types/babel__traverse": "
|
|
72
|
+
"@types/babel__traverse": "7.20.7",
|
|
71
73
|
"@types/fs-extra": "11.0.1",
|
|
72
74
|
"@types/mime-types": "2.1.4",
|
|
73
|
-
"@types/node": "22.
|
|
75
|
+
"@types/node": "22.14.1",
|
|
74
76
|
"@types/normalize-path": "3.0.2",
|
|
75
77
|
"@types/react": "19.0.10",
|
|
76
78
|
"@types/react-dom": "19.0.4",
|
|
77
79
|
"@types/webpack": "5.28.5",
|
|
78
|
-
|
|
79
|
-
autoprefixer: "10.4.20",
|
|
80
|
+
autoprefixer: "10.4.21",
|
|
80
81
|
clsx: "2.1.1",
|
|
81
|
-
"framer-motion": "12.
|
|
82
|
+
"framer-motion": "12.7.5",
|
|
82
83
|
jiti: "2.4.2",
|
|
83
84
|
json5: "2.2.3",
|
|
84
85
|
"module-punycode": "npm:punycode@2.3.1",
|
|
85
|
-
"node-html-parser": "
|
|
86
|
-
postcss: "8.
|
|
87
|
-
"prettier-plugin-tailwindcss": "0.6.6",
|
|
86
|
+
"node-html-parser": "7.0.1",
|
|
87
|
+
postcss: "8.5.3",
|
|
88
88
|
"pretty-bytes": "6.1.1",
|
|
89
|
-
"prism-react-renderer": "2.1
|
|
89
|
+
"prism-react-renderer": "2.4.1",
|
|
90
90
|
react: "19.0.0",
|
|
91
91
|
"react-dom": "19.0.0",
|
|
92
|
-
sharp: "0.
|
|
93
|
-
"socket.io-client": "4.8.
|
|
94
|
-
sonner: "
|
|
95
|
-
"source-map-js": "1.
|
|
92
|
+
sharp: "0.34.1",
|
|
93
|
+
"socket.io-client": "4.8.1",
|
|
94
|
+
sonner: "2.0.3",
|
|
95
|
+
"source-map-js": "1.2.1",
|
|
96
96
|
spamc: "0.0.5",
|
|
97
|
-
"stacktrace-parser": "0.1.
|
|
98
|
-
"tailwind-merge": "
|
|
97
|
+
"stacktrace-parser": "0.1.11",
|
|
98
|
+
"tailwind-merge": "3.2.0",
|
|
99
99
|
tailwindcss: "3.4.0",
|
|
100
|
-
tsup: "
|
|
101
|
-
tsx: "4.
|
|
102
|
-
typescript: "5.8.
|
|
100
|
+
tsup: "8.4.0",
|
|
101
|
+
tsx: "4.19.3",
|
|
102
|
+
typescript: "5.8.3",
|
|
103
103
|
"use-debounce": "10.0.4",
|
|
104
|
-
zod: "3.24.
|
|
104
|
+
zod: "3.24.3"
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
107
|
|
|
@@ -115,17 +115,26 @@ import ora2 from "ora";
|
|
|
115
115
|
// src/utils/get-emails-directory-metadata.ts
|
|
116
116
|
import fs from "node:fs";
|
|
117
117
|
import path from "node:path";
|
|
118
|
-
var isFileAnEmail = (fullPath) => {
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
var isFileAnEmail = async (fullPath) => {
|
|
119
|
+
let fileHandle;
|
|
120
|
+
try {
|
|
121
|
+
fileHandle = await fs.promises.open(fullPath, "r");
|
|
122
|
+
} catch (exception) {
|
|
123
|
+
console.warn(exception);
|
|
121
124
|
return false;
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
}
|
|
126
|
+
const stat = await fileHandle.stat();
|
|
127
|
+
if (stat.isDirectory()) {
|
|
128
|
+
await fileHandle.close();
|
|
124
129
|
return false;
|
|
125
|
-
|
|
130
|
+
}
|
|
131
|
+
const { ext } = path.parse(fullPath);
|
|
132
|
+
if (![".js", ".tsx", ".jsx"].includes(ext)) {
|
|
133
|
+
await fileHandle.close();
|
|
126
134
|
return false;
|
|
127
135
|
}
|
|
128
|
-
const fileContents =
|
|
136
|
+
const fileContents = await fileHandle.readFile("utf8");
|
|
137
|
+
await fileHandle.close();
|
|
129
138
|
const hasES6DefaultExport = /\bexport\s+default\b/gm.test(fileContents);
|
|
130
139
|
const hasCommonJSExport = /\bmodule\.exports\s*=/gm.test(fileContents);
|
|
131
140
|
const hasNamedExport = /\bexport\s+\{[^}]*\bdefault\b[^}]*\}/gm.test(
|
|
@@ -148,14 +157,16 @@ var mergeDirectoriesWithSubDirectories = (emailsDirectoryMetadata) => {
|
|
|
148
157
|
return currentResultingMergedDirectory;
|
|
149
158
|
};
|
|
150
159
|
var getEmailsDirectoryMetadata = async (absolutePathToEmailsDirectory, keepFileExtensions = false, isSubDirectory = false, baseDirectoryPath = absolutePathToEmailsDirectory) => {
|
|
151
|
-
if (!fs.existsSync(absolutePathToEmailsDirectory))
|
|
152
|
-
return;
|
|
160
|
+
if (!fs.existsSync(absolutePathToEmailsDirectory)) return;
|
|
153
161
|
const dirents = await fs.promises.readdir(absolutePathToEmailsDirectory, {
|
|
154
162
|
withFileTypes: true
|
|
155
163
|
});
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
const isEmailPredicates = await Promise.all(
|
|
165
|
+
dirents.map(
|
|
166
|
+
(dirent) => isFileAnEmail(path.join(absolutePathToEmailsDirectory, dirent.name))
|
|
167
|
+
)
|
|
168
|
+
);
|
|
169
|
+
const emailFilenames = dirents.filter((_, i) => isEmailPredicates[i]).map(
|
|
159
170
|
(dirent) => keepFileExtensions ? dirent.name : dirent.name.replace(path.extname(dirent.name), "")
|
|
160
171
|
);
|
|
161
172
|
const subDirectories = await Promise.all(
|
|
@@ -212,76 +223,19 @@ var registerSpinnerAutostopping = (spinner) => {
|
|
|
212
223
|
spinners.add(spinner);
|
|
213
224
|
};
|
|
214
225
|
|
|
215
|
-
// src/cli/utils/tree.ts
|
|
216
|
-
import { promises as fs2 } from "node:fs";
|
|
217
|
-
import os from "node:os";
|
|
218
|
-
import path2 from "node:path";
|
|
219
|
-
var SYMBOLS = {
|
|
220
|
-
BRANCH: "\u251C\u2500\u2500 ",
|
|
221
|
-
EMPTY: "",
|
|
222
|
-
INDENT: " ",
|
|
223
|
-
LAST_BRANCH: "\u2514\u2500\u2500 ",
|
|
224
|
-
VERTICAL: "\u2502 "
|
|
225
|
-
};
|
|
226
|
-
var getTreeLines = async (dirPath, depth, currentDepth = 0) => {
|
|
227
|
-
const base = process.cwd();
|
|
228
|
-
const dirFullpath = path2.resolve(base, dirPath);
|
|
229
|
-
const dirname = path2.basename(dirFullpath);
|
|
230
|
-
let lines = [dirname];
|
|
231
|
-
const dirStat = await fs2.stat(dirFullpath);
|
|
232
|
-
if (dirStat.isDirectory() && currentDepth < depth) {
|
|
233
|
-
const childDirents = await fs2.readdir(dirFullpath, { withFileTypes: true });
|
|
234
|
-
childDirents.sort((a, b) => {
|
|
235
|
-
if (a.isDirectory() && b.isFile()) {
|
|
236
|
-
return -1;
|
|
237
|
-
}
|
|
238
|
-
if (a.isFile() && b.isDirectory()) {
|
|
239
|
-
return 1;
|
|
240
|
-
}
|
|
241
|
-
return b.name > a.name ? -1 : 1;
|
|
242
|
-
});
|
|
243
|
-
for (let i = 0; i < childDirents.length; i++) {
|
|
244
|
-
const dirent = childDirents[i];
|
|
245
|
-
const isLast = i === childDirents.length - 1;
|
|
246
|
-
const branchingSymbol = isLast ? SYMBOLS.LAST_BRANCH : SYMBOLS.BRANCH;
|
|
247
|
-
const verticalSymbol = isLast ? SYMBOLS.INDENT : SYMBOLS.VERTICAL;
|
|
248
|
-
if (dirent.isFile()) {
|
|
249
|
-
lines.push(`${branchingSymbol}${dirent.name}`);
|
|
250
|
-
} else {
|
|
251
|
-
const pathToDirectory = path2.join(dirFullpath, dirent.name);
|
|
252
|
-
const treeLinesForSubDirectory = await getTreeLines(
|
|
253
|
-
pathToDirectory,
|
|
254
|
-
depth,
|
|
255
|
-
currentDepth + 1
|
|
256
|
-
);
|
|
257
|
-
lines = lines.concat(
|
|
258
|
-
treeLinesForSubDirectory.map(
|
|
259
|
-
(line, index) => index === 0 ? `${branchingSymbol}${line}` : `${verticalSymbol}${line}`
|
|
260
|
-
)
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return lines;
|
|
266
|
-
};
|
|
267
|
-
var tree = async (dirPath, depth) => {
|
|
268
|
-
const lines = await getTreeLines(dirPath, depth);
|
|
269
|
-
return lines.join(os.EOL);
|
|
270
|
-
};
|
|
271
|
-
|
|
272
226
|
// src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts
|
|
273
|
-
import
|
|
227
|
+
import path6 from "node:path";
|
|
274
228
|
import { watch } from "chokidar";
|
|
275
229
|
import debounce from "debounce";
|
|
276
230
|
import { Server as SocketServer } from "socket.io";
|
|
277
231
|
|
|
278
232
|
// src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
|
|
279
|
-
import {
|
|
280
|
-
import
|
|
233
|
+
import { existsSync as existsSync2, promises as fs3, statSync } from "node:fs";
|
|
234
|
+
import path5 from "node:path";
|
|
281
235
|
|
|
282
236
|
// src/cli/utils/preview/start-dev-server.ts
|
|
283
237
|
import http from "node:http";
|
|
284
|
-
import
|
|
238
|
+
import path4 from "node:path";
|
|
285
239
|
import url from "node:url";
|
|
286
240
|
import chalk from "chalk";
|
|
287
241
|
import logSymbols2 from "log-symbols";
|
|
@@ -289,28 +243,33 @@ import next from "next";
|
|
|
289
243
|
import ora from "ora";
|
|
290
244
|
|
|
291
245
|
// src/cli/utils/preview/get-env-variables-for-preview-app.ts
|
|
292
|
-
import
|
|
246
|
+
import path2 from "node:path";
|
|
293
247
|
var getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, cwd) => {
|
|
294
248
|
return {
|
|
295
249
|
EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
|
|
296
|
-
EMAILS_DIR_ABSOLUTE_PATH:
|
|
250
|
+
EMAILS_DIR_ABSOLUTE_PATH: path2.resolve(cwd, relativePathToEmailsDirectory),
|
|
297
251
|
USER_PROJECT_LOCATION: cwd,
|
|
298
252
|
NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
|
|
299
253
|
};
|
|
300
254
|
};
|
|
301
255
|
|
|
302
256
|
// src/cli/utils/preview/serve-static-file.ts
|
|
303
|
-
import { promises as
|
|
304
|
-
import
|
|
257
|
+
import { existsSync, promises as fs2 } from "node:fs";
|
|
258
|
+
import path3 from "node:path";
|
|
305
259
|
import { lookup } from "mime-types";
|
|
306
260
|
var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
const fileAbsolutePath =
|
|
261
|
+
const pathname = parsedUrl.pathname.replace("/static", "./static");
|
|
262
|
+
const ext = path3.parse(pathname).ext;
|
|
263
|
+
const staticBaseDir = path3.resolve(process.cwd(), staticDirRelativePath);
|
|
264
|
+
const fileAbsolutePath = path3.resolve(staticBaseDir, pathname);
|
|
265
|
+
if (!fileAbsolutePath.startsWith(staticBaseDir)) {
|
|
266
|
+
res.statusCode = 403;
|
|
267
|
+
res.end();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
311
270
|
try {
|
|
312
|
-
const fileHandle = await
|
|
313
|
-
const fileData = await
|
|
271
|
+
const fileHandle = await fs2.open(fileAbsolutePath, "r");
|
|
272
|
+
const fileData = await fs2.readFile(fileHandle);
|
|
314
273
|
res.setHeader("Content-type", lookup(ext) || "text/plain");
|
|
315
274
|
res.end(fileData);
|
|
316
275
|
fileHandle.close();
|
|
@@ -346,9 +305,11 @@ var safeAsyncServerListen = (server, port) => {
|
|
|
346
305
|
});
|
|
347
306
|
});
|
|
348
307
|
};
|
|
349
|
-
var
|
|
350
|
-
var
|
|
351
|
-
var
|
|
308
|
+
var filename = url.fileURLToPath(import.meta.url);
|
|
309
|
+
var dirname = path4.dirname(filename);
|
|
310
|
+
var isDev = !filename.endsWith(path4.join("cli", "index.mjs"));
|
|
311
|
+
var cliPackageLocation = isDev ? path4.resolve(dirname, "../../../..") : path4.resolve(dirname, "../..");
|
|
312
|
+
var previewServerLocation = isDev ? path4.resolve(dirname, "../../../..") : path4.resolve(dirname, "../preview");
|
|
352
313
|
var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
|
|
353
314
|
devServer = http.createServer((req, res) => {
|
|
354
315
|
if (!req.url) {
|
|
@@ -415,7 +376,7 @@ var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, po
|
|
|
415
376
|
...process.env,
|
|
416
377
|
...getEnvVariablesForPreviewApp(
|
|
417
378
|
// If we don't do normalization here, stuff like https://github.com/resend/react-email/issues/1354 happens.
|
|
418
|
-
|
|
379
|
+
path4.normalize(emailsDirRelativePath),
|
|
419
380
|
process.cwd()
|
|
420
381
|
)
|
|
421
382
|
};
|
|
@@ -513,9 +474,9 @@ var getImportedModules = (contents) => {
|
|
|
513
474
|
// src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
|
|
514
475
|
var readAllFilesInsideDirectory = async (directory) => {
|
|
515
476
|
let allFilePaths = [];
|
|
516
|
-
const topLevelDirents = await
|
|
477
|
+
const topLevelDirents = await fs3.readdir(directory, { withFileTypes: true });
|
|
517
478
|
for await (const dirent of topLevelDirents) {
|
|
518
|
-
const pathToDirent =
|
|
479
|
+
const pathToDirent = path5.join(directory, dirent.name);
|
|
519
480
|
if (dirent.isDirectory()) {
|
|
520
481
|
allFilePaths = allFilePaths.concat(
|
|
521
482
|
await readAllFilesInsideDirectory(pathToDirent)
|
|
@@ -527,7 +488,7 @@ var readAllFilesInsideDirectory = async (directory) => {
|
|
|
527
488
|
return allFilePaths;
|
|
528
489
|
};
|
|
529
490
|
var isJavascriptModule = (filePath) => {
|
|
530
|
-
const extensionName =
|
|
491
|
+
const extensionName = path5.extname(filePath);
|
|
531
492
|
return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
|
|
532
493
|
};
|
|
533
494
|
var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
|
|
@@ -565,23 +526,23 @@ var createDependencyGraph = async (directory) => {
|
|
|
565
526
|
])
|
|
566
527
|
);
|
|
567
528
|
const getDependencyPaths = async (filePath) => {
|
|
568
|
-
const contents = await
|
|
569
|
-
const importedPaths = getImportedModules(contents);
|
|
529
|
+
const contents = await fs3.readFile(filePath, "utf8");
|
|
530
|
+
const importedPaths = isJavascriptModule(filePath) ? getImportedModules(contents) : [];
|
|
570
531
|
const importedPathsRelativeToDirectory = importedPaths.map(
|
|
571
532
|
(dependencyPath) => {
|
|
572
533
|
const isModulePath = !dependencyPath.startsWith(".");
|
|
573
|
-
if (isModulePath ||
|
|
534
|
+
if (isModulePath || path5.isAbsolute(dependencyPath)) {
|
|
574
535
|
return dependencyPath;
|
|
575
536
|
}
|
|
576
|
-
let pathToDependencyFromDirectory =
|
|
537
|
+
let pathToDependencyFromDirectory = path5.resolve(
|
|
577
538
|
/*
|
|
578
539
|
path.resolve resolves paths differently from what imports on javascript do.
|
|
579
540
|
|
|
580
|
-
So if we wouldn't do this, for an email at "/path/to/email.tsx" with a
|
|
541
|
+
So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependency path of "./other-email"
|
|
581
542
|
would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
|
|
582
543
|
one the import is meant to go to
|
|
583
544
|
*/
|
|
584
|
-
|
|
545
|
+
path5.dirname(filePath),
|
|
585
546
|
dependencyPath
|
|
586
547
|
);
|
|
587
548
|
let isDirectory = false;
|
|
@@ -603,9 +564,7 @@ var createDependencyGraph = async (directory) => {
|
|
|
603
564
|
}
|
|
604
565
|
}
|
|
605
566
|
if (!isJavascriptModule(pathToDependencyFromDirectory)) {
|
|
606
|
-
const pathWithExtension = checkFileExtensionsUntilItExists(
|
|
607
|
-
pathToDependencyFromDirectory
|
|
608
|
-
);
|
|
567
|
+
const pathWithExtension = path5.extname(pathToDependencyFromDirectory).length > 0 ? pathToDependencyFromDirectory : checkFileExtensionsUntilItExists(pathToDependencyFromDirectory);
|
|
609
568
|
if (pathWithExtension) {
|
|
610
569
|
pathToDependencyFromDirectory = pathWithExtension;
|
|
611
570
|
} else if (isDev) {
|
|
@@ -618,10 +577,10 @@ var createDependencyGraph = async (directory) => {
|
|
|
618
577
|
}
|
|
619
578
|
);
|
|
620
579
|
const moduleDependencies = importedPathsRelativeToDirectory.filter(
|
|
621
|
-
(dependencyPath) => !dependencyPath.startsWith(".") && !
|
|
580
|
+
(dependencyPath) => !dependencyPath.startsWith(".") && !path5.isAbsolute(dependencyPath)
|
|
622
581
|
);
|
|
623
582
|
const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
|
|
624
|
-
(dependencyPath) => dependencyPath.startsWith(".") ||
|
|
583
|
+
(dependencyPath) => dependencyPath.startsWith(".") || path5.isAbsolute(dependencyPath)
|
|
625
584
|
);
|
|
626
585
|
return {
|
|
627
586
|
dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
|
|
@@ -629,17 +588,18 @@ var createDependencyGraph = async (directory) => {
|
|
|
629
588
|
};
|
|
630
589
|
};
|
|
631
590
|
const updateModuleDependenciesInGraph = async (moduleFilePath) => {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
591
|
+
if (graph[moduleFilePath] === void 0) {
|
|
592
|
+
graph[moduleFilePath] = {
|
|
593
|
+
path: moduleFilePath,
|
|
594
|
+
dependencyPaths: [],
|
|
595
|
+
dependentPaths: [],
|
|
596
|
+
moduleDependencies: []
|
|
597
|
+
};
|
|
598
|
+
}
|
|
638
599
|
const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
|
|
639
|
-
|
|
640
|
-
for (const dependencyPath of
|
|
641
|
-
if (newDependencyPaths.includes(dependencyPath))
|
|
642
|
-
continue;
|
|
600
|
+
graph[moduleFilePath].moduleDependencies = moduleDependencies;
|
|
601
|
+
for (const dependencyPath of graph[moduleFilePath].dependencyPaths) {
|
|
602
|
+
if (newDependencyPaths.includes(dependencyPath)) continue;
|
|
643
603
|
const dependencyModule = graph[dependencyPath];
|
|
644
604
|
if (dependencyModule !== void 0) {
|
|
645
605
|
dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter(
|
|
@@ -647,21 +607,21 @@ var createDependencyGraph = async (directory) => {
|
|
|
647
607
|
);
|
|
648
608
|
}
|
|
649
609
|
}
|
|
650
|
-
|
|
651
|
-
for (const dependencyPath of newDependencyPaths) {
|
|
610
|
+
graph[moduleFilePath].dependencyPaths = newDependencyPaths;
|
|
611
|
+
for await (const dependencyPath of newDependencyPaths) {
|
|
612
|
+
if (graph[dependencyPath] === void 0) {
|
|
613
|
+
await updateModuleDependenciesInGraph(dependencyPath);
|
|
614
|
+
}
|
|
652
615
|
const dependencyModule = graph[dependencyPath];
|
|
653
|
-
if (dependencyModule
|
|
616
|
+
if (dependencyModule === void 0) {
|
|
617
|
+
throw new Error(
|
|
618
|
+
`Loading the dependency path ${dependencyPath} did not initialize it at all. This is a bug in React Email.`
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
if (!dependencyModule.dependentPaths.includes(moduleFilePath)) {
|
|
654
622
|
dependencyModule.dependentPaths.push(moduleFilePath);
|
|
655
|
-
} else {
|
|
656
|
-
graph[dependencyPath] = {
|
|
657
|
-
path: dependencyPath,
|
|
658
|
-
moduleDependencies: [],
|
|
659
|
-
dependencyPaths: [],
|
|
660
|
-
dependentPaths: [moduleFilePath]
|
|
661
|
-
};
|
|
662
623
|
}
|
|
663
624
|
}
|
|
664
|
-
graph[moduleFilePath] = module;
|
|
665
625
|
};
|
|
666
626
|
for (const filePath of modulePaths) {
|
|
667
627
|
await updateModuleDependenciesInGraph(filePath);
|
|
@@ -746,11 +706,19 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
746
706
|
let changes = [];
|
|
747
707
|
const reload = debounce(() => {
|
|
748
708
|
clients.forEach((client) => {
|
|
749
|
-
client.emit(
|
|
709
|
+
client.emit(
|
|
710
|
+
"reload",
|
|
711
|
+
changes.filter(
|
|
712
|
+
(change) => (
|
|
713
|
+
// Ensures only changes inside the emails directory are emitted
|
|
714
|
+
path6.resolve(absolutePathToEmailsDirectory, change.filename).startsWith(absolutePathToEmailsDirectory)
|
|
715
|
+
)
|
|
716
|
+
)
|
|
717
|
+
);
|
|
750
718
|
});
|
|
751
719
|
changes = [];
|
|
752
720
|
}, 150);
|
|
753
|
-
const absolutePathToEmailsDirectory =
|
|
721
|
+
const absolutePathToEmailsDirectory = path6.resolve(
|
|
754
722
|
process.cwd(),
|
|
755
723
|
emailDirRelativePath
|
|
756
724
|
);
|
|
@@ -760,7 +728,7 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
760
728
|
cwd: absolutePathToEmailsDirectory
|
|
761
729
|
});
|
|
762
730
|
const getFilesOutsideEmailsDirectory = () => Object.keys(dependencyGraph).filter(
|
|
763
|
-
(p) =>
|
|
731
|
+
(p) => path6.relative(absolutePathToEmailsDirectory, p).startsWith("..")
|
|
764
732
|
);
|
|
765
733
|
let filesOutsideEmailsDirectory = getFilesOutsideEmailsDirectory();
|
|
766
734
|
for (const p of filesOutsideEmailsDirectory) {
|
|
@@ -772,11 +740,11 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
772
740
|
process.on("SIGINT", exit);
|
|
773
741
|
process.on("uncaughtException", exit);
|
|
774
742
|
watcher.on("all", async (event, relativePathToChangeTarget) => {
|
|
775
|
-
const file = relativePathToChangeTarget.split(
|
|
743
|
+
const file = relativePathToChangeTarget.split(path6.sep);
|
|
776
744
|
if (file.length === 0) {
|
|
777
745
|
return;
|
|
778
746
|
}
|
|
779
|
-
const pathToChangeTarget =
|
|
747
|
+
const pathToChangeTarget = path6.resolve(
|
|
780
748
|
absolutePathToEmailsDirectory,
|
|
781
749
|
relativePathToChangeTarget
|
|
782
750
|
);
|
|
@@ -800,7 +768,7 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
800
768
|
for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
|
|
801
769
|
changes.push({
|
|
802
770
|
event: "change",
|
|
803
|
-
filename:
|
|
771
|
+
filename: path6.relative(absolutePathToEmailsDirectory, dependentPath)
|
|
804
772
|
});
|
|
805
773
|
}
|
|
806
774
|
reload();
|
|
@@ -808,6 +776,63 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
808
776
|
return watcher;
|
|
809
777
|
};
|
|
810
778
|
|
|
779
|
+
// src/cli/utils/tree.ts
|
|
780
|
+
import { promises as fs4 } from "node:fs";
|
|
781
|
+
import os from "node:os";
|
|
782
|
+
import path7 from "node:path";
|
|
783
|
+
var SYMBOLS = {
|
|
784
|
+
BRANCH: "\u251C\u2500\u2500 ",
|
|
785
|
+
EMPTY: "",
|
|
786
|
+
INDENT: " ",
|
|
787
|
+
LAST_BRANCH: "\u2514\u2500\u2500 ",
|
|
788
|
+
VERTICAL: "\u2502 "
|
|
789
|
+
};
|
|
790
|
+
var getTreeLines = async (dirPath, depth, currentDepth = 0) => {
|
|
791
|
+
const base = process.cwd();
|
|
792
|
+
const dirFullpath = path7.resolve(base, dirPath);
|
|
793
|
+
const dirname2 = path7.basename(dirFullpath);
|
|
794
|
+
let lines = [dirname2];
|
|
795
|
+
const dirStat = await fs4.stat(dirFullpath);
|
|
796
|
+
if (dirStat.isDirectory() && currentDepth < depth) {
|
|
797
|
+
const childDirents = await fs4.readdir(dirFullpath, { withFileTypes: true });
|
|
798
|
+
childDirents.sort((a, b) => {
|
|
799
|
+
if (a.isDirectory() && b.isFile()) {
|
|
800
|
+
return -1;
|
|
801
|
+
}
|
|
802
|
+
if (a.isFile() && b.isDirectory()) {
|
|
803
|
+
return 1;
|
|
804
|
+
}
|
|
805
|
+
return b.name > a.name ? -1 : 1;
|
|
806
|
+
});
|
|
807
|
+
for (let i = 0; i < childDirents.length; i++) {
|
|
808
|
+
const dirent = childDirents[i];
|
|
809
|
+
const isLast = i === childDirents.length - 1;
|
|
810
|
+
const branchingSymbol = isLast ? SYMBOLS.LAST_BRANCH : SYMBOLS.BRANCH;
|
|
811
|
+
const verticalSymbol = isLast ? SYMBOLS.INDENT : SYMBOLS.VERTICAL;
|
|
812
|
+
if (dirent.isFile()) {
|
|
813
|
+
lines.push(`${branchingSymbol}${dirent.name}`);
|
|
814
|
+
} else {
|
|
815
|
+
const pathToDirectory = path7.join(dirFullpath, dirent.name);
|
|
816
|
+
const treeLinesForSubDirectory = await getTreeLines(
|
|
817
|
+
pathToDirectory,
|
|
818
|
+
depth,
|
|
819
|
+
currentDepth + 1
|
|
820
|
+
);
|
|
821
|
+
lines = lines.concat(
|
|
822
|
+
treeLinesForSubDirectory.map(
|
|
823
|
+
(line, index) => index === 0 ? `${branchingSymbol}${line}` : `${verticalSymbol}${line}`
|
|
824
|
+
)
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return lines;
|
|
830
|
+
};
|
|
831
|
+
var tree = async (dirPath, depth) => {
|
|
832
|
+
const lines = await getTreeLines(dirPath, depth);
|
|
833
|
+
return lines.join(os.EOL);
|
|
834
|
+
};
|
|
835
|
+
|
|
811
836
|
// src/cli/commands/build.ts
|
|
812
837
|
var buildPreviewApp = (absoluteDirectory) => {
|
|
813
838
|
return new Promise((resolve, reject) => {
|
|
@@ -875,8 +900,8 @@ var getEmailSlugsFromEmailDirectory = (emailDirectory, emailsDirectoryAbsolutePa
|
|
|
875
900
|
const directoryPathRelativeToEmailsDirectory = emailDirectory.absolutePath.replace(emailsDirectoryAbsolutePath, "").trim();
|
|
876
901
|
const slugs = [];
|
|
877
902
|
emailDirectory.emailFilenames.forEach(
|
|
878
|
-
(
|
|
879
|
-
path8.join(directoryPathRelativeToEmailsDirectory,
|
|
903
|
+
(filename2) => slugs.push(
|
|
904
|
+
path8.join(directoryPathRelativeToEmailsDirectory, filename2).split(path8.sep).filter((segment) => segment.length > 0)
|
|
880
905
|
)
|
|
881
906
|
);
|
|
882
907
|
emailDirectory.subDirectories.forEach((directory) => {
|
|
@@ -1116,7 +1141,7 @@ var renderingUtilitiesExporter = (emailTemplates) => ({
|
|
|
1116
1141
|
var getEmailTemplatesFromDirectory = (emailDirectory) => {
|
|
1117
1142
|
const templatePaths = [];
|
|
1118
1143
|
emailDirectory.emailFilenames.forEach(
|
|
1119
|
-
(
|
|
1144
|
+
(filename2) => templatePaths.push(path10.join(emailDirectory.absolutePath, filename2))
|
|
1120
1145
|
);
|
|
1121
1146
|
emailDirectory.subDirectories.forEach((directory) => {
|
|
1122
1147
|
templatePaths.push(...getEmailTemplatesFromDirectory(directory));
|
|
@@ -1300,6 +1325,6 @@ program.command("export").description("Build the templates to the `out` director
|
|
|
1300
1325
|
"To, or not to show a spinner with process information",
|
|
1301
1326
|
false
|
|
1302
1327
|
).action(
|
|
1303
|
-
({ outDir, pretty, plainText, silent, dir: srcDir }) => exportTemplates(outDir, srcDir, {
|
|
1328
|
+
({ outDir, pretty, plainText, silent, dir: srcDir }) => exportTemplates(outDir, srcDir, { silent, plainText, pretty })
|
|
1304
1329
|
);
|
|
1305
1330
|
program.parse();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3apYH6rky7aNn7g4RIJp5
|