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.
Files changed (73) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cli/index.mjs +205 -180
  3. package/dist/preview/.next/BUILD_ID +1 -1
  4. package/dist/preview/.next/app-build-manifest.json +14 -14
  5. package/dist/preview/.next/build-manifest.json +2 -2
  6. package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
  7. package/dist/preview/.next/next-server.js.nft.json +1 -1
  8. package/dist/preview/.next/prerender-manifest.json +3 -3
  9. package/dist/preview/.next/server/app/_not-found/page.js +1 -1
  10. package/dist/preview/.next/server/app/_not-found/page.js.nft.json +1 -1
  11. package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  12. package/dist/preview/.next/server/app/page.js +1 -1
  13. package/dist/preview/.next/server/app/page.js.nft.json +1 -1
  14. package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
  15. package/dist/preview/.next/server/app/preview/[...slug]/page.js +137 -75
  16. package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
  17. package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
  18. package/dist/preview/.next/server/chunks/267.js +14 -0
  19. package/dist/preview/.next/server/chunks/346.js +1 -0
  20. package/dist/preview/.next/server/chunks/{886.js → 775.js} +3 -3
  21. package/dist/preview/.next/server/pages/500.html +1 -1
  22. package/dist/preview/.next/server/server-reference-manifest.js +1 -1
  23. package/dist/preview/.next/server/server-reference-manifest.json +1 -1
  24. package/dist/preview/.next/static/chunks/33-ff3f70a80570ecda.js +1 -0
  25. package/dist/preview/.next/static/chunks/416-9c899340cfaa07d4.js +1 -0
  26. package/dist/preview/.next/static/chunks/516-2716d86d2f8b9000.js +1 -0
  27. package/dist/preview/.next/static/chunks/{587-2b8de61789f0fd1b.js → 587-0644242ce9489212.js} +1 -1
  28. package/dist/preview/.next/static/chunks/app/{layout-a3d4e7b4de277118.js → layout-2726a60e293495d3.js} +1 -1
  29. package/dist/preview/.next/static/chunks/app/{page-0ee3a37f3a3f6f17.js → page-1d98e2313c60dd77.js} +1 -1
  30. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-c77ff9f2bb1709b3.js +1 -0
  31. package/dist/preview/.next/static/chunks/f33a14d2-a04f3be0523bd1fa.js +6 -0
  32. package/dist/preview/.next/static/css/6f42d128f111d7fa.css +3 -0
  33. package/dist/preview/.next/trace +27 -27
  34. package/package.json +44 -46
  35. package/src/actions/email-validation/check-compatibility.ts +1 -1
  36. package/src/actions/email-validation/check-images.spec.tsx +1 -1
  37. package/src/actions/email-validation/check-links.spec.tsx +1 -1
  38. package/src/actions/email-validation/quick-fetch.ts +1 -1
  39. package/src/actions/render-email-by-path.tsx +6 -6
  40. package/src/app/preview/[...slug]/preview.tsx +1 -1
  41. package/src/components/toolbar.tsx +1 -0
  42. package/src/contexts/emails.tsx +1 -3
  43. package/src/contexts/fragment-identifier.tsx +3 -1
  44. package/src/contexts/preview.tsx +1 -3
  45. package/src/hooks/use-email-rendering-result.ts +18 -5
  46. package/src/hooks/use-hot-reload.ts +1 -1
  47. package/src/utils/__snapshots__/get-email-component.spec.ts.snap +1 -1
  48. package/src/utils/caniemail/ast/get-object-variables.ts +1 -1
  49. package/src/utils/caniemail/tailwind/generate-tailwind-rules.ts +1 -1
  50. package/src/utils/caniemail/tailwind/get-tailwind-config.ts +1 -1
  51. package/src/utils/caniemail/tailwind/get-tailwind-metadata.ts +1 -1
  52. package/src/utils/contains-email-template.spec.ts +107 -0
  53. package/src/utils/contains-email-template.ts +33 -0
  54. package/src/utils/get-email-component.ts +16 -1
  55. package/src/utils/get-emails-directory-metadata.ts +24 -13
  56. package/src/utils/index.ts +2 -2
  57. package/src/utils/run-bundled-code.ts +1 -1
  58. package/tailwind.config.ts +2 -1
  59. package/tsconfig.json +1 -1
  60. package/dist/cli/index.d.mts +0 -1
  61. package/dist/cli/index.d.ts +0 -1
  62. package/dist/cli/index.js +0 -1320
  63. package/dist/index.js +0 -1234
  64. package/dist/preview/.next/server/chunks/265.js +0 -1
  65. package/dist/preview/.next/server/chunks/840.js +0 -14
  66. package/dist/preview/.next/static/chunks/246-e7336e2929971f63.js +0 -1
  67. package/dist/preview/.next/static/chunks/539-6e9405ecdc007bb7.js +0 -1
  68. package/dist/preview/.next/static/chunks/853-a01d49f63a859f3d.js +0 -1
  69. package/dist/preview/.next/static/chunks/afa401a5-55858bf5265319eb.js +0 -6
  70. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-cab7e5e69e3b91e2.js +0 -1
  71. package/dist/preview/.next/static/css/67e57230289273a9.css +0 -3
  72. /package/dist/preview/.next/static/{t22IN7aANTezJAJOfFnv- → 3apYH6rky7aNn7g4RIJp5}/_buildManifest.js +0 -0
  73. /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
@@ -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.8",
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.js"
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: ["react", "email"],
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.24.5",
42
- "@babel/traverse": "7.25.6",
43
- chalk: "4.1.2",
44
- chokidar: "4.0.3",
45
- commander: "11.1.0",
46
- debounce: "2.0.0",
47
- esbuild: "0.25.0",
48
- glob: "10.3.4",
49
- "log-symbols": "4.1.0",
50
- "mime-types": "2.1.35",
51
- next: "15.2.4",
52
- "normalize-path": "3.0.0",
53
- ora: "5.4.1",
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.12.3",
59
- "@radix-ui/colors": "1.0.1",
60
- "@radix-ui/react-collapsible": "1.1.0",
61
- "@radix-ui/react-dropdown-menu": "2.1.4",
62
- "@radix-ui/react-popover": "1.1.1",
63
- "@radix-ui/react-slot": "1.1.0",
64
- "@radix-ui/react-tabs": "1.1.1",
65
- "@radix-ui/react-toggle-group": "1.1.0",
66
- "@radix-ui/react-tooltip": "1.1.2",
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.4.15",
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.10.2",
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
- "@vercel/style-guide": "5.1.0",
79
- autoprefixer: "10.4.20",
80
+ autoprefixer: "10.4.21",
80
81
  clsx: "2.1.1",
81
- "framer-motion": "12.0.0-alpha.2",
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": "6.1.13",
86
- postcss: "8.4.40",
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.0",
89
+ "prism-react-renderer": "2.4.1",
90
90
  react: "19.0.0",
91
91
  "react-dom": "19.0.0",
92
- sharp: "0.33.3",
93
- "socket.io-client": "4.8.0",
94
- sonner: "1.7.1",
95
- "source-map-js": "1.0.2",
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.10",
98
- "tailwind-merge": "2.2.0",
97
+ "stacktrace-parser": "0.1.11",
98
+ "tailwind-merge": "3.2.0",
99
99
  tailwindcss: "3.4.0",
100
- tsup: "7.2.0",
101
- tsx: "4.9.0",
102
- typescript: "5.8.2",
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.2"
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
- const stat = fs.statSync(fullPath);
120
- if (stat.isDirectory())
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
- const { ext } = path.parse(fullPath);
123
- if (![".js", ".tsx", ".jsx"].includes(ext))
125
+ }
126
+ const stat = await fileHandle.stat();
127
+ if (stat.isDirectory()) {
128
+ await fileHandle.close();
124
129
  return false;
125
- if (!fs.existsSync(fullPath)) {
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 = fs.readFileSync(fullPath, "utf8");
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 emailFilenames = dirents.filter(
157
- (dirent) => isFileAnEmail(path.join(absolutePathToEmailsDirectory, dirent.name))
158
- ).map(
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 path7 from "node:path";
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 { promises as fs4, existsSync as existsSync2, statSync } from "node:fs";
280
- import path6 from "node:path";
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 path5 from "node:path";
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 path3 from "node:path";
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: path3.resolve(cwd, relativePathToEmailsDirectory),
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 fs3, existsSync } from "node:fs";
304
- import path4 from "node:path";
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 staticBaseDir = path4.join(process.cwd(), staticDirRelativePath);
308
- const pathname = parsedUrl.pathname;
309
- const ext = path4.parse(pathname).ext;
310
- const fileAbsolutePath = path4.join(staticBaseDir, pathname);
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 fs3.open(fileAbsolutePath, "r");
313
- const fileData = await fs3.readFile(fileHandle);
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 isDev = !__filename.endsWith(path5.join("cli", "index.js"));
350
- var cliPackageLocation = isDev ? path5.resolve(__dirname, "../../../..") : path5.resolve(__dirname, "../..");
351
- var previewServerLocation = isDev ? path5.resolve(__dirname, "../../../..") : path5.resolve(__dirname, "../preview");
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
- path5.normalize(emailsDirRelativePath),
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 fs4.readdir(directory, { withFileTypes: true });
477
+ const topLevelDirents = await fs3.readdir(directory, { withFileTypes: true });
517
478
  for await (const dirent of topLevelDirents) {
518
- const pathToDirent = path6.join(directory, dirent.name);
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 = path6.extname(filePath);
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 fs4.readFile(filePath, "utf8");
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 || path6.isAbsolute(dependencyPath)) {
534
+ if (isModulePath || path5.isAbsolute(dependencyPath)) {
574
535
  return dependencyPath;
575
536
  }
576
- let pathToDependencyFromDirectory = path6.resolve(
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 dependecy path of "./other-email"
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
- path6.dirname(filePath),
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(".") && !path6.isAbsolute(dependencyPath)
580
+ (dependencyPath) => !dependencyPath.startsWith(".") && !path5.isAbsolute(dependencyPath)
622
581
  );
623
582
  const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
624
- (dependencyPath) => dependencyPath.startsWith(".") || path6.isAbsolute(dependencyPath)
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
- const module = graph[moduleFilePath] ?? {
633
- path: moduleFilePath,
634
- dependencyPaths: [],
635
- dependentPaths: [],
636
- moduleDependencies: []
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
- module.moduleDependencies = moduleDependencies;
640
- for (const dependencyPath of module.dependencyPaths) {
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
- module.dependencyPaths = newDependencyPaths;
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 !== void 0 && !dependencyModule.dependentPaths.includes(moduleFilePath)) {
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("reload", changes);
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 = path7.resolve(
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) => path7.relative(absolutePathToEmailsDirectory, p).startsWith("..")
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(path7.sep);
743
+ const file = relativePathToChangeTarget.split(path6.sep);
776
744
  if (file.length === 0) {
777
745
  return;
778
746
  }
779
- const pathToChangeTarget = path7.resolve(
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: path7.relative(absolutePathToEmailsDirectory, dependentPath)
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
- (filename) => slugs.push(
879
- path8.join(directoryPathRelativeToEmailsDirectory, filename).split(path8.sep).filter((segment) => segment.length > 0)
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
- (filename) => templatePaths.push(path10.join(emailDirectory.absolutePath, filename))
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, { pretty, silent, plainText })
1328
+ ({ outDir, pretty, plainText, silent, dir: srcDir }) => exportTemplates(outDir, srcDir, { silent, plainText, pretty })
1304
1329
  );
1305
1330
  program.parse();
@@ -1 +1 @@
1
- t22IN7aANTezJAJOfFnv-
1
+ 3apYH6rky7aNn7g4RIJp5