react-email 3.0.5 → 3.0.7-canary.0

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 (192) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cli/index.js +764 -769
  3. package/dist/cli/index.mjs +488 -499
  4. package/dist/preview/.next/BUILD_ID +1 -1
  5. package/dist/preview/.next/app-build-manifest.json +10 -10
  6. package/dist/preview/.next/build-manifest.json +3 -3
  7. package/dist/preview/.next/cache/.rscinfo +1 -1
  8. package/dist/preview/.next/cache/webpack/client-production/0.pack +0 -0
  9. package/dist/preview/.next/cache/webpack/client-production/index.pack +0 -0
  10. package/dist/preview/.next/cache/webpack/edge-server-production/index.pack +0 -0
  11. package/dist/preview/.next/cache/webpack/server-production/0.pack +0 -0
  12. package/dist/preview/.next/cache/webpack/server-production/index.pack +0 -0
  13. package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
  14. package/dist/preview/.next/next-server.js.nft.json +1 -1
  15. package/dist/preview/.next/prerender-manifest.json +1 -1
  16. package/dist/preview/.next/required-server-files.json +1 -1
  17. package/dist/preview/.next/server/app/_not-found/page.js +1 -1
  18. package/dist/preview/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/dist/preview/.next/server/app/favicon.ico/route.js +1 -1
  21. package/dist/preview/.next/server/app/page.js +1 -1
  22. package/dist/preview/.next/server/app/page.js.nft.json +1 -1
  23. package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
  24. package/dist/preview/.next/server/app/preview/[...slug]/page.js +7 -6
  25. package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
  26. package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
  27. package/dist/preview/.next/server/chunks/196.js +5 -0
  28. package/dist/preview/.next/server/chunks/650.js +1 -0
  29. package/dist/preview/.next/server/chunks/720.js +3 -3
  30. package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
  31. package/dist/preview/.next/server/next-font-manifest.js +1 -1
  32. package/dist/preview/.next/server/next-font-manifest.json +1 -1
  33. package/dist/preview/.next/server/pages/500.html +1 -1
  34. package/dist/preview/.next/server/server-reference-manifest.js +1 -1
  35. package/dist/preview/.next/server/server-reference-manifest.json +1 -1
  36. package/dist/preview/.next/static/chunks/154-ca55c1fde27d0922.js +1 -0
  37. package/dist/preview/.next/static/chunks/app/layout-7b9224888c7ffd05.js +1 -0
  38. package/dist/preview/.next/static/chunks/app/page-36853df2e13e583f.js +1 -0
  39. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-48ce00470ce06446.js +1 -0
  40. package/dist/preview/.next/static/chunks/main-app-cd104297c6bcc87e.js +1 -0
  41. package/dist/preview/.next/static/css/{eb0a93282704d7ab.css → a34876a6c565fff8.css} +1 -1
  42. package/dist/preview/.next/trace +21 -20
  43. package/dist/preview/.next/types/app/layout.ts +1 -1
  44. package/dist/preview/.next/types/app/preview/[...slug]/page.ts +1 -1
  45. package/package.json +4 -8
  46. package/postcss.config.js +1 -1
  47. package/src/actions/get-email-path-from-slug.ts +7 -4
  48. package/src/actions/get-emails-directory-metadata-action.ts +19 -0
  49. package/src/actions/render-email-by-path.tsx +3 -3
  50. package/src/app/layout.tsx +2 -2
  51. package/src/app/page.tsx +1 -1
  52. package/src/app/preview/[...slug]/page.tsx +2 -2
  53. package/src/app/preview/[...slug]/preview.tsx +2 -2
  54. package/src/components/button.tsx +1 -1
  55. package/src/components/code-container.tsx +1 -1
  56. package/src/components/heading.tsx +1 -1
  57. package/src/components/sidebar/sidebar-directory-children.tsx +5 -8
  58. package/src/components/sidebar/sidebar-directory.tsx +2 -2
  59. package/src/components/sidebar/sidebar.tsx +2 -2
  60. package/src/components/text.tsx +1 -1
  61. package/src/components/tooltip-content.tsx +1 -1
  62. package/src/components/tooltip.tsx +1 -1
  63. package/src/components/topbar.tsx +1 -1
  64. package/src/contexts/emails.tsx +3 -5
  65. package/src/hooks/use-email-rendering-result.ts +2 -2
  66. package/src/utils/cn.ts +1 -1
  67. package/src/utils/esbuild/renderring-utilities-exporter.ts +1 -1
  68. package/src/utils/get-email-component.ts +6 -6
  69. package/src/{actions → utils}/get-emails-directory-metadata.spec.ts +1 -2
  70. package/src/utils/get-emails-directory-metadata.ts +119 -0
  71. package/src/utils/improve-error-with-sourcemap.ts +1 -1
  72. package/src/utils/static-node-modules-for-vm.ts +6 -6
  73. package/tsconfig.json +1 -6
  74. package/.eslintrc.js +0 -52
  75. package/.prettierignore +0 -3
  76. package/.prettierrc.js +0 -8
  77. package/dist/index.d.mts +0 -20
  78. package/dist/index.d.ts +0 -20
  79. package/dist/index.js +0 -96
  80. package/dist/index.mjs +0 -21
  81. package/dist/package/index.d.mts +0 -33
  82. package/dist/package/index.d.ts +0 -33
  83. package/dist/package/index.js +0 -62
  84. package/dist/package/index.mjs +0 -7
  85. package/dist/preview/.next/cache/eslint/.cache_1vyas3k +0 -1
  86. package/dist/preview/.next/server/chunks/420.js +0 -1
  87. package/dist/preview/.next/server/chunks/625.js +0 -5
  88. package/dist/preview/.next/static/chunks/154-69b91a0c2fd801b8.js +0 -1
  89. package/dist/preview/.next/static/chunks/app/layout-e1b6f1534cbbe5bd.js +0 -1
  90. package/dist/preview/.next/static/chunks/app/page-2c3e297e38c526ef.js +0 -1
  91. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-2b4988ba6daf34e1.js +0 -1
  92. package/dist/preview/.next/static/chunks/main-app-2c7f96205a73f128.js +0 -1
  93. package/src/actions/get-emails-directory-metadata.ts +0 -123
  94. package/src/package/body/dist/index.d.mts +0 -6
  95. package/src/package/body/dist/index.d.ts +0 -6
  96. package/src/package/body/dist/index.js +0 -79
  97. package/src/package/body/dist/index.mjs +0 -45
  98. package/src/package/button/dist/index.d.mts +0 -6
  99. package/src/package/button/dist/index.d.ts +0 -6
  100. package/src/package/button/dist/index.js +0 -252
  101. package/src/package/button/dist/index.mjs +0 -218
  102. package/src/package/code-block/dist/index.d.mts +0 -4906
  103. package/src/package/code-block/dist/index.d.ts +0 -4906
  104. package/src/package/code-block/dist/index.js +0 -18205
  105. package/src/package/code-block/dist/index.mjs +0 -18133
  106. package/src/package/code-inline/dist/index.d.mts +0 -11
  107. package/src/package/code-inline/dist/index.d.ts +0 -11
  108. package/src/package/code-inline/dist/index.js +0 -106
  109. package/src/package/code-inline/dist/index.mjs +0 -72
  110. package/src/package/column/dist/index.d.mts +0 -6
  111. package/src/package/column/dist/index.d.ts +0 -6
  112. package/src/package/column/dist/index.js +0 -79
  113. package/src/package/column/dist/index.mjs +0 -45
  114. package/src/package/components/dist/index.d.mts +0 -20
  115. package/src/package/components/dist/index.d.ts +0 -20
  116. package/src/package/components/dist/index.js +0 -62
  117. package/src/package/components/dist/index.mjs +0 -21
  118. package/src/package/container/dist/index.d.mts +0 -6
  119. package/src/package/container/dist/index.d.ts +0 -6
  120. package/src/package/container/dist/index.js +0 -93
  121. package/src/package/container/dist/index.mjs +0 -59
  122. package/src/package/font/dist/index.d.mts +0 -25
  123. package/src/package/font/dist/index.d.ts +0 -25
  124. package/src/package/font/dist/index.js +0 -55
  125. package/src/package/font/dist/index.mjs +0 -28
  126. package/src/package/head/dist/index.d.mts +0 -6
  127. package/src/package/head/dist/index.d.ts +0 -6
  128. package/src/package/head/dist/index.js +0 -83
  129. package/src/package/head/dist/index.mjs +0 -49
  130. package/src/package/heading/dist/index.d.mts +0 -43
  131. package/src/package/heading/dist/index.d.ts +0 -43
  132. package/src/package/heading/dist/index.js +0 -113
  133. package/src/package/heading/dist/index.mjs +0 -79
  134. package/src/package/hr/dist/index.d.mts +0 -6
  135. package/src/package/hr/dist/index.d.ts +0 -6
  136. package/src/package/hr/dist/index.js +0 -89
  137. package/src/package/hr/dist/index.mjs +0 -55
  138. package/src/package/html/dist/index.d.mts +0 -6
  139. package/src/package/html/dist/index.d.ts +0 -6
  140. package/src/package/html/dist/index.js +0 -79
  141. package/src/package/html/dist/index.mjs +0 -45
  142. package/src/package/img/dist/index.d.mts +0 -6
  143. package/src/package/img/dist/index.d.ts +0 -6
  144. package/src/package/img/dist/index.js +0 -94
  145. package/src/package/img/dist/index.mjs +0 -60
  146. package/src/package/link/dist/index.d.mts +0 -6
  147. package/src/package/link/dist/index.d.ts +0 -6
  148. package/src/package/link/dist/index.js +0 -90
  149. package/src/package/link/dist/index.mjs +0 -56
  150. package/src/package/markdown/dist/index.d.mts +0 -15
  151. package/src/package/markdown/dist/index.d.ts +0 -15
  152. package/src/package/markdown/dist/index.js +0 -92
  153. package/src/package/markdown/dist/index.mjs +0 -58
  154. package/src/package/preview/dist/index.d.mts +0 -12
  155. package/src/package/preview/dist/index.d.ts +0 -12
  156. package/src/package/preview/dist/index.js +0 -108
  157. package/src/package/preview/dist/index.mjs +0 -73
  158. package/src/package/render/dist/browser/index.d.mts +0 -24
  159. package/src/package/render/dist/browser/index.d.ts +0 -24
  160. package/src/package/render/dist/browser/index.js +0 -250
  161. package/src/package/render/dist/browser/index.mjs +0 -214
  162. package/src/package/render/dist/index.d.mts +0 -23
  163. package/src/package/render/dist/index.d.ts +0 -23
  164. package/src/package/render/dist/index.js +0 -768
  165. package/src/package/render/dist/index.mjs +0 -733
  166. package/src/package/render/dist/node/index.d.mts +0 -27
  167. package/src/package/render/dist/node/index.d.ts +0 -27
  168. package/src/package/render/dist/node/index.js +0 -212
  169. package/src/package/render/dist/node/index.mjs +0 -176
  170. package/src/package/row/dist/index.d.mts +0 -10
  171. package/src/package/row/dist/index.d.ts +0 -10
  172. package/src/package/row/dist/index.js +0 -93
  173. package/src/package/row/dist/index.mjs +0 -59
  174. package/src/package/section/dist/index.d.mts +0 -6
  175. package/src/package/section/dist/index.d.ts +0 -6
  176. package/src/package/section/dist/index.js +0 -93
  177. package/src/package/section/dist/index.mjs +0 -59
  178. package/src/package/tailwind/dist/index.d.ts +0 -19
  179. package/src/package/tailwind/dist/index.js +0 -48
  180. package/src/package/tailwind/dist/index.mjs +0 -17167
  181. package/src/package/tailwind/dist/tailwindcss/config.d.ts +0 -376
  182. package/src/package/tailwind/dist/tailwindcss/generated/.gitkeep +0 -0
  183. package/src/package/tailwind/dist/tailwindcss/generated/colors.d.ts +0 -298
  184. package/src/package/tailwind/dist/tailwindcss/generated/corePluginList.d.ts +0 -1
  185. package/src/package/tailwind/dist/tailwindcss/generated/default-theme.d.ts +0 -397
  186. package/src/package/tailwind/dist/tailwindcss/index.d.ts +0 -11
  187. package/src/package/text/dist/index.d.mts +0 -6
  188. package/src/package/text/dist/index.d.ts +0 -6
  189. package/src/package/text/dist/index.js +0 -89
  190. package/src/package/text/dist/index.mjs +0 -55
  191. /package/dist/preview/.next/static/{6K68y2QEZ1dLbv-Xhi30p → 3Ni4t_kYMdpL72HxSPHgK}/_buildManifest.js +0 -0
  192. /package/dist/preview/.next/static/{6K68y2QEZ1dLbv-Xhi30p → 3Ni4t_kYMdpL72HxSPHgK}/_ssgManifest.js +0 -0
@@ -13,7 +13,7 @@ import { program } from "commander";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "react-email",
16
- version: "3.0.5",
16
+ version: "3.0.7-canary.0",
17
17
  description: "A live preview of your emails right in your browser.",
18
18
  bin: {
19
19
  email: "./dist/cli/index.js"
@@ -23,8 +23,7 @@ var package_default = {
23
23
  dev: "tsup-node --watch",
24
24
  test: "vitest run",
25
25
  "test:watch": "vitest",
26
- clean: "rm -rf dist",
27
- lint: "eslint . && tsc"
26
+ clean: "rm -rf dist"
28
27
  },
29
28
  license: "MIT",
30
29
  repository: {
@@ -32,10 +31,7 @@ var package_default = {
32
31
  url: "https://github.com/resend/react-email.git",
33
32
  directory: "packages/react-email"
34
33
  },
35
- keywords: [
36
- "react",
37
- "email"
38
- ],
34
+ keywords: ["react", "email"],
39
35
  engines: {
40
36
  node: ">=18.0.0"
41
37
  },
@@ -46,7 +42,7 @@ var package_default = {
46
42
  chokidar: "4.0.3",
47
43
  commander: "11.1.0",
48
44
  debounce: "2.0.0",
49
- esbuild: "0.19.11",
45
+ esbuild: "0.23.0",
50
46
  glob: "10.3.4",
51
47
  "log-symbols": "4.1.0",
52
48
  "mime-types": "2.1.35",
@@ -75,9 +71,6 @@ var package_default = {
75
71
  "@vercel/style-guide": "5.1.0",
76
72
  autoprefixer: "10.4.20",
77
73
  clsx: "2.1.0",
78
- eslint: "8.50.0",
79
- "eslint-config-prettier": "9.0.0",
80
- "eslint-config-turbo": "2.1.0",
81
74
  "framer-motion": "12.0.0-alpha.2",
82
75
  postcss: "8.4.40",
83
76
  "prism-react-renderer": "2.1.0",
@@ -97,13 +90,112 @@ var package_default = {
97
90
  }
98
91
  };
99
92
 
100
- // src/cli/commands/dev.ts
101
- import fs4 from "node:fs";
93
+ // src/cli/commands/build.ts
94
+ import { spawn } from "node:child_process";
95
+ import fs5 from "node:fs";
96
+ import path8 from "node:path";
97
+ import logSymbols3 from "log-symbols";
98
+ import ora2 from "ora";
99
+
100
+ // src/utils/get-emails-directory-metadata.ts
101
+ import fs from "node:fs";
102
+ import path from "node:path";
103
+ var isFileAnEmail = (fullPath) => {
104
+ const stat = fs.statSync(fullPath);
105
+ if (stat.isDirectory())
106
+ return false;
107
+ const { ext } = path.parse(fullPath);
108
+ if (![".js", ".tsx", ".jsx"].includes(ext))
109
+ return false;
110
+ if (!fs.existsSync(fullPath)) {
111
+ return false;
112
+ }
113
+ const fileContents = fs.readFileSync(fullPath, "utf8");
114
+ return /\bexport\s+default\b/gm.test(fileContents);
115
+ };
116
+ var mergeDirectoriesWithSubDirectories = (emailsDirectoryMetadata) => {
117
+ let currentResultingMergedDirectory = emailsDirectoryMetadata;
118
+ while (currentResultingMergedDirectory.emailFilenames.length === 0 && currentResultingMergedDirectory.subDirectories.length === 1) {
119
+ const onlySubDirectory = currentResultingMergedDirectory.subDirectories[0];
120
+ currentResultingMergedDirectory = {
121
+ ...onlySubDirectory,
122
+ directoryName: path.join(
123
+ currentResultingMergedDirectory.directoryName,
124
+ onlySubDirectory.directoryName
125
+ )
126
+ };
127
+ }
128
+ return currentResultingMergedDirectory;
129
+ };
130
+ var getEmailsDirectoryMetadata = async (absolutePathToEmailsDirectory, keepFileExtensions = false, isSubDirectory = false, baseDirectoryPath = absolutePathToEmailsDirectory) => {
131
+ if (!fs.existsSync(absolutePathToEmailsDirectory))
132
+ return;
133
+ const dirents = await fs.promises.readdir(absolutePathToEmailsDirectory, {
134
+ withFileTypes: true
135
+ });
136
+ const emailFilenames = dirents.filter(
137
+ (dirent) => isFileAnEmail(path.join(absolutePathToEmailsDirectory, dirent.name))
138
+ ).map(
139
+ (dirent) => keepFileExtensions ? dirent.name : dirent.name.replace(path.extname(dirent.name), "")
140
+ );
141
+ const subDirectories = await Promise.all(
142
+ dirents.filter(
143
+ (dirent) => dirent.isDirectory() && !dirent.name.startsWith("_") && dirent.name !== "static"
144
+ ).map((dirent) => {
145
+ const direntAbsolutePath = path.join(
146
+ absolutePathToEmailsDirectory,
147
+ dirent.name
148
+ );
149
+ return getEmailsDirectoryMetadata(
150
+ direntAbsolutePath,
151
+ keepFileExtensions,
152
+ true,
153
+ baseDirectoryPath
154
+ );
155
+ })
156
+ );
157
+ const emailsMetadata = {
158
+ absolutePath: absolutePathToEmailsDirectory,
159
+ relativePath: path.relative(
160
+ baseDirectoryPath,
161
+ absolutePathToEmailsDirectory
162
+ ),
163
+ directoryName: absolutePathToEmailsDirectory.split(path.sep).pop(),
164
+ emailFilenames,
165
+ subDirectories
166
+ };
167
+ return isSubDirectory ? mergeDirectoriesWithSubDirectories(emailsMetadata) : emailsMetadata;
168
+ };
169
+
170
+ // src/utils/register-spinner-autostopping.ts
171
+ import logSymbols from "log-symbols";
172
+ var spinners = /* @__PURE__ */ new Set();
173
+ process.on("SIGINT", () => {
174
+ spinners.forEach((spinner) => {
175
+ if (spinner.isSpinning) {
176
+ spinner.stop();
177
+ }
178
+ });
179
+ });
180
+ process.on("exit", (code) => {
181
+ if (code !== 0) {
182
+ spinners.forEach((spinner) => {
183
+ if (spinner.isSpinning) {
184
+ spinner.stopAndPersist({
185
+ symbol: logSymbols.error
186
+ });
187
+ }
188
+ });
189
+ }
190
+ });
191
+ var registerSpinnerAutostopping = (spinner) => {
192
+ spinners.add(spinner);
193
+ };
102
194
 
103
195
  // src/cli/utils/tree.ts
104
- import { promises as fs } from "node:fs";
196
+ import { promises as fs2 } from "node:fs";
105
197
  import os from "node:os";
106
- import path from "node:path";
198
+ import path2 from "node:path";
107
199
  var SYMBOLS = {
108
200
  BRANCH: "\u251C\u2500\u2500 ",
109
201
  EMPTY: "",
@@ -113,12 +205,12 @@ var SYMBOLS = {
113
205
  };
114
206
  var getTreeLines = async (dirPath, depth, currentDepth = 0) => {
115
207
  const base = process.cwd();
116
- const dirFullpath = path.resolve(base, dirPath);
117
- const dirname = path.basename(dirFullpath);
208
+ const dirFullpath = path2.resolve(base, dirPath);
209
+ const dirname = path2.basename(dirFullpath);
118
210
  let lines = [dirname];
119
- const dirStat = await fs.stat(dirFullpath);
211
+ const dirStat = await fs2.stat(dirFullpath);
120
212
  if (dirStat.isDirectory() && currentDepth < depth) {
121
- const childDirents = await fs.readdir(dirFullpath, { withFileTypes: true });
213
+ const childDirents = await fs2.readdir(dirFullpath, { withFileTypes: true });
122
214
  childDirents.sort((a, b) => {
123
215
  if (a.isDirectory() && b.isFile()) {
124
216
  return -1;
@@ -136,7 +228,7 @@ var getTreeLines = async (dirPath, depth, currentDepth = 0) => {
136
228
  if (dirent.isFile()) {
137
229
  lines.push(`${branchingSymbol}${dirent.name}`);
138
230
  } else {
139
- const pathToDirectory = path.join(dirFullpath, dirent.name);
231
+ const pathToDirectory = path2.join(dirFullpath, dirent.name);
140
232
  const treeLinesForSubDirectory = await getTreeLines(
141
233
  pathToDirectory,
142
234
  depth,
@@ -158,98 +250,46 @@ var tree = async (dirPath, depth) => {
158
250
  };
159
251
 
160
252
  // src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts
161
- import path6 from "node:path";
162
- import { Server as SocketServer } from "socket.io";
253
+ import path7 from "node:path";
163
254
  import { watch } from "chokidar";
164
255
  import debounce from "debounce";
256
+ import { Server as SocketServer } from "socket.io";
165
257
 
166
258
  // src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
167
- import path5 from "node:path";
168
- import { existsSync, promises as fs3, statSync } from "node:fs";
169
-
170
- // src/cli/utils/preview/hot-reloading/get-imported-modules.ts
171
- import { traverse } from "@babel/core";
172
- import { parse } from "@babel/parser";
173
- var getImportedModules = (contents) => {
174
- const importedPaths = [];
175
- const parsedContents = parse(contents, {
176
- sourceType: "unambiguous",
177
- strictMode: false,
178
- errorRecovery: true,
179
- plugins: ["jsx", "typescript", "decorators"]
180
- });
181
- traverse(parsedContents, {
182
- ImportDeclaration({ node }) {
183
- importedPaths.push(node.source.value);
184
- },
185
- ExportAllDeclaration({ node }) {
186
- importedPaths.push(node.source.value);
187
- },
188
- ExportNamedDeclaration({ node }) {
189
- if (node.source) {
190
- importedPaths.push(node.source.value);
191
- }
192
- },
193
- CallExpression({ node }) {
194
- if ("name" in node.callee && node.callee.name === "require") {
195
- if (node.arguments.length === 1) {
196
- const importPathNode = node.arguments[0];
197
- if (importPathNode.type === "StringLiteral") {
198
- importedPaths.push(importPathNode.value);
199
- }
200
- }
201
- }
202
- }
203
- });
204
- return importedPaths;
205
- };
259
+ import { promises as fs4, existsSync, statSync } from "node:fs";
260
+ import path6 from "node:path";
206
261
 
207
262
  // src/cli/utils/preview/start-dev-server.ts
208
- import path4 from "node:path";
209
263
  import http from "node:http";
264
+ import path5 from "node:path";
210
265
  import url from "node:url";
266
+ import chalk from "chalk";
267
+ import logSymbols2 from "log-symbols";
211
268
  import next from "next";
212
269
  import ora from "ora";
213
- import logSymbols2 from "log-symbols";
214
- import chalk from "chalk";
215
270
 
216
- // src/utils/register-spinner-autostopping.ts
217
- import logSymbols from "log-symbols";
218
- var spinners = /* @__PURE__ */ new Set();
219
- process.on("SIGINT", () => {
220
- spinners.forEach((spinner) => {
221
- if (spinner.isSpinning) {
222
- spinner.stop();
223
- }
224
- });
225
- });
226
- process.on("exit", (code) => {
227
- if (code !== 0) {
228
- spinners.forEach((spinner) => {
229
- if (spinner.isSpinning) {
230
- spinner.stopAndPersist({
231
- symbol: logSymbols.error
232
- });
233
- }
234
- });
235
- }
236
- });
237
- var registerSpinnerAutostopping = (spinner) => {
238
- spinners.add(spinner);
271
+ // src/cli/utils/preview/get-env-variables-for-preview-app.ts
272
+ import path3 from "node:path";
273
+ var getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, cwd) => {
274
+ return {
275
+ EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
276
+ EMAILS_DIR_ABSOLUTE_PATH: path3.resolve(cwd, relativePathToEmailsDirectory),
277
+ USER_PROJECT_LOCATION: cwd
278
+ };
239
279
  };
240
280
 
241
281
  // src/cli/utils/preview/serve-static-file.ts
242
- import path2 from "node:path";
243
- import { promises as fs2 } from "node:fs";
282
+ import { promises as fs3 } from "node:fs";
283
+ import path4 from "node:path";
244
284
  import { lookup } from "mime-types";
245
285
  var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
246
- const staticBaseDir = path2.join(process.cwd(), staticDirRelativePath);
286
+ const staticBaseDir = path4.join(process.cwd(), staticDirRelativePath);
247
287
  const pathname = parsedUrl.pathname;
248
- const ext = path2.parse(pathname).ext;
249
- let fileAbsolutePath = path2.join(staticBaseDir, pathname);
250
- const fileHandle = await fs2.open(fileAbsolutePath, "r");
288
+ const ext = path4.parse(pathname).ext;
289
+ const fileAbsolutePath = path4.join(staticBaseDir, pathname);
290
+ const fileHandle = await fs3.open(fileAbsolutePath, "r");
251
291
  try {
252
- const fileData = await fs2.readFile(fileHandle);
292
+ const fileData = await fs3.readFile(fileHandle);
253
293
  res.setHeader("Content-type", lookup(ext) || "text/plain");
254
294
  res.end(fileData);
255
295
  } catch (exception) {
@@ -266,16 +306,6 @@ var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
266
306
  }
267
307
  };
268
308
 
269
- // src/cli/utils/preview/get-env-variables-for-preview-app.ts
270
- import path3 from "node:path";
271
- var getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, cwd) => {
272
- return {
273
- EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
274
- EMAILS_DIR_ABSOLUTE_PATH: path3.resolve(cwd, relativePathToEmailsDirectory),
275
- USER_PROJECT_LOCATION: cwd
276
- };
277
- };
278
-
279
309
  // src/cli/utils/preview/start-dev-server.ts
280
310
  var devServer;
281
311
  var safeAsyncServerListen = (server, port) => {
@@ -290,9 +320,9 @@ var safeAsyncServerListen = (server, port) => {
290
320
  });
291
321
  });
292
322
  };
293
- var isDev = !__filename.endsWith(path4.join("cli", "index.js"));
294
- var cliPacakgeLocation = isDev ? path4.resolve(__dirname, "../../../..") : path4.resolve(__dirname, "../..");
295
- var previewServerLocation = isDev ? path4.resolve(__dirname, "../../../..") : path4.resolve(__dirname, "../preview");
323
+ var isDev = !__filename.endsWith(path5.join("cli", "index.js"));
324
+ var cliPacakgeLocation = isDev ? path5.resolve(__dirname, "../../../..") : path5.resolve(__dirname, "../..");
325
+ var previewServerLocation = isDev ? path5.resolve(__dirname, "../../../..") : path5.resolve(__dirname, "../preview");
296
326
  var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
297
327
  devServer = http.createServer((req, res) => {
298
328
  if (!req.url) {
@@ -307,7 +337,7 @@ var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, po
307
337
  res.setHeader("Pragma", "no-cache");
308
338
  res.setHeader("Expires", "-1");
309
339
  try {
310
- if (parsedUrl.path && parsedUrl.path.includes("static/") && !parsedUrl.path.includes("_next/static/")) {
340
+ if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) {
311
341
  void serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
312
342
  } else if (!isNextReady) {
313
343
  void nextReadyPromise.then(
@@ -355,11 +385,11 @@ var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, po
355
385
  registerSpinnerAutostopping(spinner);
356
386
  const timeBeforeNextReady = performance.now();
357
387
  process.env = {
358
- ...process.env,
359
388
  NODE_ENV: "development",
389
+ ...process.env,
360
390
  ...getEnvVariablesForPreviewApp(
361
391
  // If we don't do normalization here, stuff like https://github.com/resend/react-email/issues/1354 happens.
362
- path4.normalize(emailsDirRelativePath),
392
+ path5.normalize(emailsDirRelativePath),
363
393
  process.cwd()
364
394
  )
365
395
  };
@@ -417,12 +447,49 @@ process.on(
417
447
  makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
418
448
  );
419
449
 
450
+ // src/cli/utils/preview/hot-reloading/get-imported-modules.ts
451
+ import { traverse } from "@babel/core";
452
+ import { parse } from "@babel/parser";
453
+ var getImportedModules = (contents) => {
454
+ const importedPaths = [];
455
+ const parsedContents = parse(contents, {
456
+ sourceType: "unambiguous",
457
+ strictMode: false,
458
+ errorRecovery: true,
459
+ plugins: ["jsx", "typescript", "decorators"]
460
+ });
461
+ traverse(parsedContents, {
462
+ ImportDeclaration({ node }) {
463
+ importedPaths.push(node.source.value);
464
+ },
465
+ ExportAllDeclaration({ node }) {
466
+ importedPaths.push(node.source.value);
467
+ },
468
+ ExportNamedDeclaration({ node }) {
469
+ if (node.source) {
470
+ importedPaths.push(node.source.value);
471
+ }
472
+ },
473
+ CallExpression({ node }) {
474
+ if ("name" in node.callee && node.callee.name === "require") {
475
+ if (node.arguments.length === 1) {
476
+ const importPathNode = node.arguments[0];
477
+ if (importPathNode.type === "StringLiteral") {
478
+ importedPaths.push(importPathNode.value);
479
+ }
480
+ }
481
+ }
482
+ }
483
+ });
484
+ return importedPaths;
485
+ };
486
+
420
487
  // src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
421
488
  var readAllFilesInsideDirectory = async (directory) => {
422
489
  let allFilePaths = [];
423
- const topLevelDirents = await fs3.readdir(directory, { withFileTypes: true });
490
+ const topLevelDirents = await fs4.readdir(directory, { withFileTypes: true });
424
491
  for await (const dirent of topLevelDirents) {
425
- const pathToDirent = path5.join(directory, dirent.name);
492
+ const pathToDirent = path6.join(directory, dirent.name);
426
493
  if (dirent.isDirectory()) {
427
494
  allFilePaths = allFilePaths.concat(
428
495
  await readAllFilesInsideDirectory(pathToDirent)
@@ -434,7 +501,7 @@ var readAllFilesInsideDirectory = async (directory) => {
434
501
  return allFilePaths;
435
502
  };
436
503
  var isJavascriptModule = (filePath) => {
437
- const extensionName = path5.extname(filePath);
504
+ const extensionName = path6.extname(filePath);
438
505
  return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
439
506
  };
440
507
  var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
@@ -472,64 +539,63 @@ var createDependencyGraph = async (directory) => {
472
539
  ])
473
540
  );
474
541
  const getDependencyPaths = async (filePath) => {
475
- const contents = await fs3.readFile(filePath, "utf8");
542
+ const contents = await fs4.readFile(filePath, "utf8");
476
543
  const importedPaths = getImportedModules(contents);
477
544
  const importedPathsRelativeToDirectory = importedPaths.map(
478
545
  (dependencyPath) => {
479
546
  const isModulePath = !dependencyPath.startsWith(".");
480
- if (!isModulePath && !path5.isAbsolute(dependencyPath)) {
481
- let pathToDependencyFromDirectory = path5.resolve(
482
- /*
483
- path.resolve resolves paths differently from what imports on javascript do.
484
-
485
- So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependecy path of "./other-email"
486
- would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
487
- one the import is meant to go to
488
- */
489
- path5.dirname(filePath),
490
- dependencyPath
547
+ if (isModulePath || path6.isAbsolute(dependencyPath)) {
548
+ return dependencyPath;
549
+ }
550
+ let pathToDependencyFromDirectory = path6.resolve(
551
+ /*
552
+ path.resolve resolves paths differently from what imports on javascript do.
553
+
554
+ So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependecy path of "./other-email"
555
+ would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
556
+ one the import is meant to go to
557
+ */
558
+ path6.dirname(filePath),
559
+ dependencyPath
560
+ );
561
+ let isDirectory = false;
562
+ try {
563
+ isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
564
+ } catch (_) {
565
+ }
566
+ if (isDirectory) {
567
+ const pathToSubDirectory = pathToDependencyFromDirectory;
568
+ const pathWithExtension = checkFileExtensionsUntilItExists(
569
+ `${pathToSubDirectory}/index`
491
570
  );
492
- let isDirectory = false;
493
- try {
494
- isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
495
- } catch (_) {
496
- }
497
- if (isDirectory) {
498
- const pathToSubDirectory = pathToDependencyFromDirectory;
499
- const pathWithExtension = checkFileExtensionsUntilItExists(
500
- `${pathToSubDirectory}/index`
571
+ if (pathWithExtension) {
572
+ pathToDependencyFromDirectory = pathWithExtension;
573
+ } else if (isDev) {
574
+ console.warn(
575
+ `Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
501
576
  );
502
- if (pathWithExtension) {
503
- pathToDependencyFromDirectory = pathWithExtension;
504
- } else if (isDev) {
505
- console.warn(
506
- `Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
507
- );
508
- }
509
577
  }
510
- if (!isJavascriptModule(pathToDependencyFromDirectory)) {
511
- const pathWithExtension = checkFileExtensionsUntilItExists(
512
- pathToDependencyFromDirectory
578
+ }
579
+ if (!isJavascriptModule(pathToDependencyFromDirectory)) {
580
+ const pathWithExtension = checkFileExtensionsUntilItExists(
581
+ pathToDependencyFromDirectory
582
+ );
583
+ if (pathWithExtension) {
584
+ pathToDependencyFromDirectory = pathWithExtension;
585
+ } else if (isDev) {
586
+ console.warn(
587
+ `Could not determine the file extension for the file at ${pathToDependencyFromDirectory}`
513
588
  );
514
- if (pathWithExtension) {
515
- pathToDependencyFromDirectory = pathWithExtension;
516
- } else if (isDev) {
517
- console.warn(
518
- `Could not determine the file extension for the file at ${pathToDependencyFromDirectory}`
519
- );
520
- }
521
589
  }
522
- return pathToDependencyFromDirectory;
523
- } else {
524
- return dependencyPath;
525
590
  }
591
+ return pathToDependencyFromDirectory;
526
592
  }
527
593
  );
528
594
  const moduleDependencies = importedPathsRelativeToDirectory.filter(
529
- (dependencyPath) => !dependencyPath.startsWith(".") && !path5.isAbsolute(dependencyPath)
595
+ (dependencyPath) => !dependencyPath.startsWith(".") && !path6.isAbsolute(dependencyPath)
530
596
  );
531
597
  const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
532
- (dependencyPath) => dependencyPath.startsWith(".") || path5.isAbsolute(dependencyPath)
598
+ (dependencyPath) => dependencyPath.startsWith(".") || path6.isAbsolute(dependencyPath)
533
599
  );
534
600
  return {
535
601
  dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
@@ -658,7 +724,7 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
658
724
  });
659
725
  changes = [];
660
726
  }, 150);
661
- const absolutePathToEmailsDirectory = path6.resolve(
727
+ const absolutePathToEmailsDirectory = path7.resolve(
662
728
  process.cwd(),
663
729
  emailDirRelativePath
664
730
  );
@@ -668,7 +734,7 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
668
734
  cwd: absolutePathToEmailsDirectory
669
735
  });
670
736
  const getFilesOutsideEmailsDirectory = () => Object.keys(dependencyGraph).filter(
671
- (p) => path6.relative(absolutePathToEmailsDirectory, p).startsWith("..")
737
+ (p) => path7.relative(absolutePathToEmailsDirectory, p).startsWith("..")
672
738
  );
673
739
  let filesOutsideEmailsDirectory = getFilesOutsideEmailsDirectory();
674
740
  for (const p of filesOutsideEmailsDirectory) {
@@ -680,11 +746,11 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
680
746
  process.on("SIGINT", exit);
681
747
  process.on("uncaughtException", exit);
682
748
  watcher.on("all", async (event, relativePathToChangeTarget) => {
683
- const file = relativePathToChangeTarget.split(path6.sep);
749
+ const file = relativePathToChangeTarget.split(path7.sep);
684
750
  if (file.length === 0) {
685
751
  return;
686
752
  }
687
- const pathToChangeTarget = path6.resolve(
753
+ const pathToChangeTarget = path7.resolve(
688
754
  absolutePathToEmailsDirectory,
689
755
  relativePathToChangeTarget
690
756
  );
@@ -708,7 +774,7 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
708
774
  for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
709
775
  changes.push({
710
776
  event: "change",
711
- filename: path6.relative(absolutePathToEmailsDirectory, dependentPath)
777
+ filename: path7.relative(absolutePathToEmailsDirectory, dependentPath)
712
778
  });
713
779
  }
714
780
  reload();
@@ -716,111 +782,256 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
716
782
  return watcher;
717
783
  };
718
784
 
719
- // src/cli/commands/dev.ts
720
- var dev = async ({ dir: emailsDirRelativePath, port }) => {
721
- try {
722
- if (!fs4.existsSync(emailsDirRelativePath)) {
723
- console.error(`Missing ${emailsDirRelativePath} folder`);
724
- process.exit(1);
725
- }
726
- const devServer2 = await startDevServer(
727
- emailsDirRelativePath,
728
- emailsDirRelativePath,
729
- // defaults to ./emails/static for the static files that are served to the preview
730
- Number.parseInt(port)
731
- );
732
- await setupHotreloading(devServer2, emailsDirRelativePath);
733
- } catch (error) {
734
- console.log(error);
735
- process.exit(1);
736
- }
785
+ // src/cli/commands/build.ts
786
+ var buildPreviewApp = (absoluteDirectory) => {
787
+ return new Promise((resolve, reject) => {
788
+ const nextBuild = spawn("npm", ["run", "build"], {
789
+ cwd: absoluteDirectory,
790
+ shell: true
791
+ });
792
+ nextBuild.stdout.pipe(process.stdout);
793
+ nextBuild.stderr.pipe(process.stderr);
794
+ nextBuild.on("close", (code) => {
795
+ if (code === 0) {
796
+ resolve();
797
+ } else {
798
+ reject(
799
+ new Error(
800
+ `Unable to build the Next app and it exited with code: ${code}`
801
+ )
802
+ );
803
+ }
804
+ });
805
+ });
737
806
  };
738
-
739
- // src/cli/commands/export.ts
740
- import fs7, { unlinkSync, writeFileSync } from "node:fs";
741
- import path9 from "node:path";
742
- import { glob } from "glob";
743
- import { build } from "esbuild";
744
- import ora2 from "ora";
745
- import logSymbols3 from "log-symbols";
746
- import normalize from "normalize-path";
747
-
748
- // src/actions/get-emails-directory-metadata.ts
749
- import fs5 from "node:fs";
750
- import path7 from "node:path";
751
- import { cache } from "react";
752
- var isFileAnEmail = (fullPath) => {
753
- const stat = fs5.statSync(fullPath);
754
- if (stat.isDirectory())
755
- return false;
756
- const { ext } = path7.parse(fullPath);
757
- if (![".js", ".tsx", ".jsx"].includes(ext))
758
- return false;
759
- if (!fs5.existsSync(fullPath)) {
760
- return false;
761
- }
762
- const fileContents = fs5.readFileSync(fullPath, "utf8");
763
- return /\bexport\s+default\b/gm.test(fileContents);
807
+ var setNextEnvironmentVariablesForBuild = async (emailsDirRelativePath, builtPreviewAppPath) => {
808
+ const nextConfigContents = `
809
+ const path = require('path');
810
+ const emailsDirRelativePath = path.normalize('${emailsDirRelativePath}');
811
+ const userProjectLocation = path.resolve(process.cwd(), '../');
812
+ /** @type {import('next').NextConfig} */
813
+ module.exports = {
814
+ env: {
815
+ NEXT_PUBLIC_IS_BUILDING: 'true',
816
+ EMAILS_DIR_RELATIVE_PATH: emailsDirRelativePath,
817
+ EMAILS_DIR_ABSOLUTE_PATH: path.resolve(userProjectLocation, emailsDirRelativePath),
818
+ USER_PROJECT_LOCATION: userProjectLocation
819
+ },
820
+ // this is needed so that the code for building emails works properly
821
+ webpack: (
822
+ /** @type {import('webpack').Configuration & { externals: string[] }} */
823
+ config,
824
+ { isServer }
825
+ ) => {
826
+ if (isServer) {
827
+ config.externals.push('esbuild');
828
+ }
829
+
830
+ return config;
831
+ },
832
+ typescript: {
833
+ ignoreBuildErrors: true
834
+ },
835
+ eslint: {
836
+ ignoreDuringBuilds: true
837
+ },
838
+ experimental: {
839
+ webpackBuildWorker: true
840
+ },
841
+ }`;
842
+ await fs5.promises.writeFile(
843
+ path8.resolve(builtPreviewAppPath, "./next.config.js"),
844
+ nextConfigContents,
845
+ "utf8"
846
+ );
764
847
  };
765
- var mergeDirectoriesWithSubDirectories = (emailsDirectoryMetadata) => {
766
- let currentResultingMergedDirectory = emailsDirectoryMetadata;
767
- while (currentResultingMergedDirectory.emailFilenames.length === 0 && currentResultingMergedDirectory.subDirectories.length === 1) {
768
- const onlySubDirectory = currentResultingMergedDirectory.subDirectories[0];
769
- currentResultingMergedDirectory = {
770
- ...onlySubDirectory,
771
- directoryName: path7.join(
772
- currentResultingMergedDirectory.directoryName,
773
- onlySubDirectory.directoryName
848
+ var getEmailSlugsFromEmailDirectory = (emailDirectory, emailsDirectoryAbsolutePath) => {
849
+ const directoryPathRelativeToEmailsDirectory = emailDirectory.absolutePath.replace(emailsDirectoryAbsolutePath, "").trim();
850
+ const slugs = [];
851
+ emailDirectory.emailFilenames.forEach(
852
+ (filename) => slugs.push(
853
+ path8.join(directoryPathRelativeToEmailsDirectory, filename).split(path8.sep).filter((segment) => segment.length > 0)
854
+ )
855
+ );
856
+ emailDirectory.subDirectories.forEach((directory) => {
857
+ slugs.push(
858
+ ...getEmailSlugsFromEmailDirectory(
859
+ directory,
860
+ emailsDirectoryAbsolutePath
774
861
  )
775
- };
776
- }
777
- return currentResultingMergedDirectory;
862
+ );
863
+ });
864
+ return slugs;
778
865
  };
779
- var getEmailsDirectoryMetadata = cache(
780
- async (absolutePathToEmailsDirectory, keepFileExtensions = false, isSubDirectory = false, baseDirectoryPath = absolutePathToEmailsDirectory) => {
781
- if (!fs5.existsSync(absolutePathToEmailsDirectory))
782
- return;
783
- const dirents = await fs5.promises.readdir(absolutePathToEmailsDirectory, {
784
- withFileTypes: true
785
- });
786
- const emailFilenames = dirents.filter(
787
- (dirent) => isFileAnEmail(path7.join(absolutePathToEmailsDirectory, dirent.name))
788
- ).map(
789
- (dirent) => keepFileExtensions ? dirent.name : dirent.name.replace(path7.extname(dirent.name), "")
866
+ var forceSSGForEmailPreviews = async (emailsDirPath, builtPreviewAppPath) => {
867
+ const emailDirectoryMetadata = (
868
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
869
+ await getEmailsDirectoryMetadata(emailsDirPath)
870
+ );
871
+ const parameters = getEmailSlugsFromEmailDirectory(
872
+ emailDirectoryMetadata,
873
+ emailsDirPath
874
+ ).map((slug) => ({ slug }));
875
+ const removeForceDynamic = async (filePath) => {
876
+ const contents = await fs5.promises.readFile(filePath, "utf8");
877
+ await fs5.promises.writeFile(
878
+ filePath,
879
+ contents.replace("export const dynamic = 'force-dynamic';", ""),
880
+ "utf8"
790
881
  );
791
- const subDirectories = await Promise.all(
792
- dirents.filter(
793
- (dirent) => dirent.isDirectory() && !dirent.name.startsWith("_") && dirent.name !== "static"
794
- ).map((dirent) => {
795
- const direntAbsolutePath = path7.join(
796
- absolutePathToEmailsDirectory,
797
- dirent.name
798
- );
799
- return getEmailsDirectoryMetadata(
800
- direntAbsolutePath,
801
- keepFileExtensions,
802
- true,
803
- baseDirectoryPath
882
+ };
883
+ await removeForceDynamic(
884
+ path8.resolve(builtPreviewAppPath, "./src/app/layout.tsx")
885
+ );
886
+ await removeForceDynamic(
887
+ path8.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx")
888
+ );
889
+ await fs5.promises.appendFile(
890
+ path8.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx"),
891
+ `
892
+
893
+ export function generateStaticParams() {
894
+ return Promise.resolve(
895
+ ${JSON.stringify(parameters)}
896
+ );
897
+ }`,
898
+ "utf8"
899
+ );
900
+ };
901
+ var updatePackageJson = async (builtPreviewAppPath) => {
902
+ const packageJsonPath = path8.resolve(builtPreviewAppPath, "./package.json");
903
+ const packageJson = JSON.parse(
904
+ await fs5.promises.readFile(packageJsonPath, "utf8")
905
+ );
906
+ packageJson.scripts.build = "next build";
907
+ packageJson.scripts.start = "next start";
908
+ packageJson.name = "preview-server";
909
+ delete packageJson.devDependencies["@react-email/render"];
910
+ delete packageJson.devDependencies["@react-email/components"];
911
+ await fs5.promises.writeFile(
912
+ packageJsonPath,
913
+ JSON.stringify(packageJson),
914
+ "utf8"
915
+ );
916
+ };
917
+ var npmInstall = async (builtPreviewAppPath, packageManager) => {
918
+ return new Promise((resolve, reject) => {
919
+ const childProc = spawn(
920
+ packageManager,
921
+ ["install", "--silent", "--include=dev"],
922
+ {
923
+ cwd: builtPreviewAppPath,
924
+ shell: true
925
+ }
926
+ );
927
+ childProc.stdout.pipe(process.stdout);
928
+ childProc.stderr.pipe(process.stderr);
929
+ childProc.on("close", (code) => {
930
+ if (code === 0) {
931
+ resolve();
932
+ } else {
933
+ reject(
934
+ new Error(
935
+ `Unable to install the dependencies and it exited with code: ${code}`
936
+ )
804
937
  );
805
- })
938
+ }
939
+ });
940
+ });
941
+ };
942
+ var build = async ({
943
+ dir: emailsDirRelativePath,
944
+ packageManager
945
+ }) => {
946
+ try {
947
+ const spinner = ora2({
948
+ text: "Starting build process...",
949
+ prefixText: " "
950
+ }).start();
951
+ registerSpinnerAutostopping(spinner);
952
+ spinner.text = `Checking if ${emailsDirRelativePath} folder exists`;
953
+ if (!fs5.existsSync(emailsDirRelativePath)) {
954
+ process.exit(1);
955
+ }
956
+ const emailsDirPath = path8.join(process.cwd(), emailsDirRelativePath);
957
+ const staticPath = path8.join(emailsDirPath, "static");
958
+ const builtPreviewAppPath = path8.join(process.cwd(), ".react-email");
959
+ if (fs5.existsSync(builtPreviewAppPath)) {
960
+ spinner.text = "Deleting pre-existing `.react-email` folder";
961
+ await fs5.promises.rm(builtPreviewAppPath, { recursive: true });
962
+ }
963
+ spinner.text = "Copying preview app from CLI to `.react-email`";
964
+ await fs5.promises.cp(cliPacakgeLocation, builtPreviewAppPath, {
965
+ recursive: true,
966
+ filter: (source) => {
967
+ return !/(\/|\\)cli(\/|\\)?/.test(source) && !/(\/|\\)\.next(\/|\\)?/.test(source) && !/(\/|\\)\.turbo(\/|\\)?/.test(source) && !/(\/|\\)node_modules(\/|\\)?$/.test(source);
968
+ }
969
+ });
970
+ if (fs5.existsSync(staticPath)) {
971
+ spinner.text = "Copying `static` folder into `.react-email/public/static`";
972
+ const builtStaticDirectory = path8.resolve(
973
+ builtPreviewAppPath,
974
+ "./public/static"
975
+ );
976
+ await fs5.promises.cp(staticPath, builtStaticDirectory, {
977
+ recursive: true
978
+ });
979
+ }
980
+ spinner.text = "Setting Next environment variables for preview app to work properly";
981
+ await setNextEnvironmentVariablesForBuild(
982
+ emailsDirRelativePath,
983
+ builtPreviewAppPath
806
984
  );
807
- const emailsMetadata = {
808
- absolutePath: absolutePathToEmailsDirectory,
809
- relativePath: path7.relative(
810
- baseDirectoryPath,
811
- absolutePathToEmailsDirectory
812
- ),
813
- directoryName: absolutePathToEmailsDirectory.split(path7.sep).pop(),
814
- emailFilenames,
815
- subDirectories
816
- };
817
- return isSubDirectory ? mergeDirectoriesWithSubDirectories(emailsMetadata) : emailsMetadata;
985
+ spinner.text = "Setting server side generation for the email preview pages";
986
+ await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
987
+ spinner.text = "Updating package.json's build and start scripts";
988
+ await updatePackageJson(builtPreviewAppPath);
989
+ spinner.text = "Installing dependencies on `.react-email`";
990
+ await npmInstall(builtPreviewAppPath, packageManager);
991
+ spinner.stopAndPersist({
992
+ text: "Successfully prepared `.react-email` for `next build`",
993
+ symbol: logSymbols3.success
994
+ });
995
+ await buildPreviewApp(builtPreviewAppPath);
996
+ } catch (error) {
997
+ console.log(error);
998
+ process.exit(1);
818
999
  }
819
- );
1000
+ };
1001
+
1002
+ // src/cli/commands/dev.ts
1003
+ import fs6 from "node:fs";
1004
+ var dev = async ({ dir: emailsDirRelativePath, port }) => {
1005
+ try {
1006
+ if (!fs6.existsSync(emailsDirRelativePath)) {
1007
+ console.error(`Missing ${emailsDirRelativePath} folder`);
1008
+ process.exit(1);
1009
+ }
1010
+ const devServer2 = await startDevServer(
1011
+ emailsDirRelativePath,
1012
+ emailsDirRelativePath,
1013
+ // defaults to ./emails/static for the static files that are served to the preview
1014
+ Number.parseInt(port)
1015
+ );
1016
+ await setupHotreloading(devServer2, emailsDirRelativePath);
1017
+ } catch (error) {
1018
+ console.log(error);
1019
+ process.exit(1);
1020
+ }
1021
+ };
1022
+
1023
+ // src/cli/commands/export.ts
1024
+ import fs8, { unlinkSync, writeFileSync } from "node:fs";
1025
+ import path10 from "node:path";
1026
+ import { build as build2 } from "esbuild";
1027
+ import { glob } from "glob";
1028
+ import logSymbols4 from "log-symbols";
1029
+ import normalize from "normalize-path";
1030
+ import ora3 from "ora";
820
1031
 
821
1032
  // src/utils/esbuild/renderring-utilities-exporter.ts
822
- import path8 from "node:path";
823
- import { promises as fs6 } from "node:fs";
1033
+ import { promises as fs7 } from "node:fs";
1034
+ import path9 from "node:path";
824
1035
 
825
1036
  // src/utils/esbuild/escape-string-for-regex.ts
826
1037
  function escapeStringForRegex(string) {
@@ -839,11 +1050,11 @@ var renderingUtilitiesExporter = (emailTemplates) => ({
839
1050
  },
840
1051
  async ({ path: pathToFile }) => {
841
1052
  return {
842
- contents: `${await fs6.readFile(pathToFile, "utf8")};
1053
+ contents: `${await fs7.readFile(pathToFile, "utf8")};
843
1054
  export { render } from 'react-email-module-that-will-export-render'
844
1055
  export { createElement as reactEmailCreateReactElement } from 'react';
845
1056
  `,
846
- loader: path8.extname(pathToFile).slice(1)
1057
+ loader: path9.extname(pathToFile).slice(1)
847
1058
  };
848
1059
  }
849
1060
  );
@@ -874,7 +1085,7 @@ var renderingUtilitiesExporter = (emailTemplates) => ({
874
1085
  var getEmailTemplatesFromDirectory = (emailDirectory) => {
875
1086
  const templatePaths = [];
876
1087
  emailDirectory.emailFilenames.forEach(
877
- (filename) => templatePaths.push(path9.join(emailDirectory.absolutePath, filename))
1088
+ (filename) => templatePaths.push(path10.join(emailDirectory.absolutePath, filename))
878
1089
  );
879
1090
  emailDirectory.subDirectories.forEach((directory) => {
880
1091
  templatePaths.push(...getEmailTemplatesFromDirectory(directory));
@@ -882,22 +1093,22 @@ var getEmailTemplatesFromDirectory = (emailDirectory) => {
882
1093
  return templatePaths;
883
1094
  };
884
1095
  var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirectoryPath, options) => {
885
- if (fs7.existsSync(pathToWhereEmailMarkupShouldBeDumped)) {
886
- fs7.rmSync(pathToWhereEmailMarkupShouldBeDumped, { recursive: true });
1096
+ if (fs8.existsSync(pathToWhereEmailMarkupShouldBeDumped)) {
1097
+ fs8.rmSync(pathToWhereEmailMarkupShouldBeDumped, { recursive: true });
887
1098
  }
888
1099
  let spinner;
889
1100
  if (!options.silent) {
890
- spinner = ora2("Preparing files...\n").start();
1101
+ spinner = ora3("Preparing files...\n").start();
891
1102
  registerSpinnerAutostopping(spinner);
892
1103
  }
893
1104
  const emailsDirectoryMetadata = await getEmailsDirectoryMetadata(
894
- path9.resolve(process.cwd(), emailsDirectoryPath),
1105
+ path10.resolve(process.cwd(), emailsDirectoryPath),
895
1106
  true
896
1107
  );
897
1108
  if (typeof emailsDirectoryMetadata === "undefined") {
898
1109
  if (spinner) {
899
1110
  spinner.stopAndPersist({
900
- symbol: logSymbols3.error,
1111
+ symbol: logSymbols4.error,
901
1112
  text: `Could not find the directory at ${emailsDirectoryPath}`
902
1113
  });
903
1114
  }
@@ -905,7 +1116,7 @@ var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirecto
905
1116
  }
906
1117
  const allTemplates = getEmailTemplatesFromDirectory(emailsDirectoryMetadata);
907
1118
  try {
908
- await build({
1119
+ await build2({
909
1120
  bundle: true,
910
1121
  entryPoints: allTemplates,
911
1122
  plugins: [renderingUtilitiesExporter(allTemplates)],
@@ -921,7 +1132,7 @@ var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirecto
921
1132
  const buildFailure = exception;
922
1133
  if (spinner) {
923
1134
  spinner.stopAndPersist({
924
- symbol: logSymbols3.error,
1135
+ symbol: logSymbols4.error,
925
1136
  text: "Failed to build emails"
926
1137
  });
927
1138
  }
@@ -957,7 +1168,7 @@ var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirecto
957
1168
  } catch (exception) {
958
1169
  if (spinner) {
959
1170
  spinner.stopAndPersist({
960
- symbol: logSymbols3.error,
1171
+ symbol: logSymbols4.error,
961
1172
  text: `failed when rendering ${template.split("/").pop()}`
962
1173
  });
963
1174
  }
@@ -970,23 +1181,23 @@ var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirecto
970
1181
  spinner.text = "Copying static files";
971
1182
  spinner.render();
972
1183
  }
973
- const staticDirectoryPath = path9.join(emailsDirectoryPath, "static");
974
- if (fs7.existsSync(staticDirectoryPath)) {
975
- const pathToDumpStaticFilesInto = path9.join(
1184
+ const staticDirectoryPath = path10.join(emailsDirectoryPath, "static");
1185
+ if (fs8.existsSync(staticDirectoryPath)) {
1186
+ const pathToDumpStaticFilesInto = path10.join(
976
1187
  pathToWhereEmailMarkupShouldBeDumped,
977
1188
  "static"
978
1189
  );
979
- if (fs7.existsSync(pathToDumpStaticFilesInto))
980
- await fs7.promises.rm(pathToDumpStaticFilesInto, { recursive: true });
1190
+ if (fs8.existsSync(pathToDumpStaticFilesInto))
1191
+ await fs8.promises.rm(pathToDumpStaticFilesInto, { recursive: true });
981
1192
  try {
982
- await fs7.promises.cp(staticDirectoryPath, pathToDumpStaticFilesInto, {
1193
+ await fs8.promises.cp(staticDirectoryPath, pathToDumpStaticFilesInto, {
983
1194
  recursive: true
984
1195
  });
985
1196
  } catch (exception) {
986
1197
  console.error(exception);
987
1198
  if (spinner) {
988
1199
  spinner.stopAndPersist({
989
- symbol: logSymbols3.error,
1200
+ symbol: logSymbols4.error,
990
1201
  text: "Failed to copy static files"
991
1202
  });
992
1203
  }
@@ -1001,238 +1212,16 @@ var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirecto
1001
1212
  const fileTree = await tree(pathToWhereEmailMarkupShouldBeDumped, 4);
1002
1213
  console.log(fileTree);
1003
1214
  spinner.stopAndPersist({
1004
- symbol: logSymbols3.success,
1215
+ symbol: logSymbols4.success,
1005
1216
  text: "Successfully exported emails"
1006
1217
  });
1007
1218
  }
1008
1219
  };
1009
1220
 
1010
- // src/cli/commands/build.ts
1011
- import fs8 from "node:fs";
1012
- import path10 from "node:path";
1013
- import ora3 from "ora";
1014
- import { spawn } from "node:child_process";
1015
- import logSymbols4 from "log-symbols";
1016
- var buildPreviewApp = (absoluteDirectory) => {
1017
- return new Promise((resolve, reject) => {
1018
- const nextBuild = spawn("npm", ["run", "build"], {
1019
- cwd: absoluteDirectory,
1020
- shell: true
1021
- });
1022
- nextBuild.stdout.pipe(process.stdout);
1023
- nextBuild.stderr.pipe(process.stderr);
1024
- nextBuild.on("close", (code) => {
1025
- if (code === 0) {
1026
- resolve();
1027
- } else {
1028
- reject(
1029
- new Error(
1030
- `Unable to build the Next app and it exited with code: ${code}`
1031
- )
1032
- );
1033
- }
1034
- });
1035
- });
1036
- };
1037
- var setNextEnvironmentVariablesForBuild = async (emailsDirRelativePath, builtPreviewAppPath) => {
1038
- const nextConfigContents = `
1039
- const path = require('path');
1040
- const emailsDirRelativePath = path.normalize('${emailsDirRelativePath}');
1041
- const userProjectLocation = path.resolve(process.cwd(), '../');
1042
- /** @type {import('next').NextConfig} */
1043
- module.exports = {
1044
- env: {
1045
- NEXT_PUBLIC_IS_BUILDING: 'true',
1046
- EMAILS_DIR_RELATIVE_PATH: emailsDirRelativePath,
1047
- EMAILS_DIR_ABSOLUTE_PATH: path.resolve(userProjectLocation, emailsDirRelativePath),
1048
- USER_PROJECT_LOCATION: userProjectLocation
1049
- },
1050
- // this is needed so that the code for building emails works properly
1051
- webpack: (
1052
- /** @type {import('webpack').Configuration & { externals: string[] }} */
1053
- config,
1054
- { isServer }
1055
- ) => {
1056
- if (isServer) {
1057
- config.externals.push('esbuild');
1058
- }
1059
-
1060
- return config;
1061
- },
1062
- typescript: {
1063
- ignoreBuildErrors: true
1064
- },
1065
- eslint: {
1066
- ignoreDuringBuilds: true
1067
- },
1068
- experimental: {
1069
- webpackBuildWorker: true
1070
- },
1071
- }`;
1072
- await fs8.promises.writeFile(
1073
- path10.resolve(builtPreviewAppPath, "./next.config.js"),
1074
- nextConfigContents,
1075
- "utf8"
1076
- );
1077
- };
1078
- var getEmailSlugsFromEmailDirectory = (emailDirectory, emailsDirectoryAbsolutePath) => {
1079
- const directoryPathRelativeToEmailsDirectory = emailDirectory.absolutePath.replace(emailsDirectoryAbsolutePath, "").trim();
1080
- const slugs = [];
1081
- emailDirectory.emailFilenames.forEach(
1082
- (filename) => slugs.push(
1083
- path10.join(directoryPathRelativeToEmailsDirectory, filename).split(path10.sep).filter((segment) => segment.length > 0)
1084
- )
1085
- );
1086
- emailDirectory.subDirectories.forEach((directory) => {
1087
- slugs.push(
1088
- ...getEmailSlugsFromEmailDirectory(
1089
- directory,
1090
- emailsDirectoryAbsolutePath
1091
- )
1092
- );
1093
- });
1094
- return slugs;
1095
- };
1096
- var forceSSGForEmailPreviews = async (emailsDirPath, builtPreviewAppPath) => {
1097
- const emailDirectoryMetadata = (
1098
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1099
- await getEmailsDirectoryMetadata(emailsDirPath)
1100
- );
1101
- const parameters = getEmailSlugsFromEmailDirectory(
1102
- emailDirectoryMetadata,
1103
- emailsDirPath
1104
- ).map((slug) => ({ slug }));
1105
- const removeForceDynamic = async (filePath) => {
1106
- const contents = await fs8.promises.readFile(filePath, "utf8");
1107
- await fs8.promises.writeFile(
1108
- filePath,
1109
- contents.replace("export const dynamic = 'force-dynamic';", ""),
1110
- "utf8"
1111
- );
1112
- };
1113
- await removeForceDynamic(
1114
- path10.resolve(builtPreviewAppPath, "./src/app/layout.tsx")
1115
- );
1116
- await removeForceDynamic(
1117
- path10.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx")
1118
- );
1119
- await fs8.promises.appendFile(
1120
- path10.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx"),
1121
- `
1122
-
1123
- export function generateStaticParams() {
1124
- return Promise.resolve(
1125
- ${JSON.stringify(parameters)}
1126
- );
1127
- }`,
1128
- "utf8"
1129
- );
1130
- };
1131
- var updatePackageJson = async (builtPreviewAppPath) => {
1132
- const packageJsonPath = path10.resolve(builtPreviewAppPath, "./package.json");
1133
- const packageJson = JSON.parse(
1134
- await fs8.promises.readFile(packageJsonPath, "utf8")
1135
- );
1136
- packageJson.scripts.build = "next build";
1137
- packageJson.scripts.start = "next start";
1138
- packageJson.name = "preview-server";
1139
- delete packageJson.devDependencies["@react-email/render"];
1140
- delete packageJson.devDependencies["@react-email/components"];
1141
- await fs8.promises.writeFile(
1142
- packageJsonPath,
1143
- JSON.stringify(packageJson),
1144
- "utf8"
1145
- );
1146
- };
1147
- var npmInstall = async (builtPreviewAppPath, packageManager) => {
1148
- return new Promise((resolve, reject) => {
1149
- const childProc = spawn(
1150
- packageManager,
1151
- ["install", "--silent", "--include=dev"],
1152
- {
1153
- cwd: builtPreviewAppPath,
1154
- shell: true
1155
- }
1156
- );
1157
- childProc.stdout.pipe(process.stdout);
1158
- childProc.stderr.pipe(process.stderr);
1159
- childProc.on("close", (code) => {
1160
- if (code === 0) {
1161
- resolve();
1162
- } else {
1163
- reject(
1164
- new Error(
1165
- `Unable to install the dependencies and it exited with code: ${code}`
1166
- )
1167
- );
1168
- }
1169
- });
1170
- });
1171
- };
1172
- var build2 = async ({
1173
- dir: emailsDirRelativePath,
1174
- packageManager
1175
- }) => {
1176
- try {
1177
- const spinner = ora3({
1178
- text: "Starting build process...",
1179
- prefixText: " "
1180
- }).start();
1181
- registerSpinnerAutostopping(spinner);
1182
- spinner.text = `Checking if ${emailsDirRelativePath} folder exists`;
1183
- if (!fs8.existsSync(emailsDirRelativePath)) {
1184
- process.exit(1);
1185
- }
1186
- const emailsDirPath = path10.join(process.cwd(), emailsDirRelativePath);
1187
- const staticPath = path10.join(emailsDirPath, "static");
1188
- const builtPreviewAppPath = path10.join(process.cwd(), ".react-email");
1189
- if (fs8.existsSync(builtPreviewAppPath)) {
1190
- spinner.text = "Deleting pre-existing `.react-email` folder";
1191
- await fs8.promises.rm(builtPreviewAppPath, { recursive: true });
1192
- }
1193
- spinner.text = "Copying preview app from CLI to `.react-email`";
1194
- await fs8.promises.cp(cliPacakgeLocation, builtPreviewAppPath, {
1195
- recursive: true,
1196
- filter: (source) => {
1197
- return !/(\/|\\)cli(\/|\\)?/.test(source) && !/(\/|\\)\.next(\/|\\)?/.test(source) && !/(\/|\\)\.turbo(\/|\\)?/.test(source) && !/(\/|\\)node_modules(\/|\\)?$/.test(source);
1198
- }
1199
- });
1200
- if (fs8.existsSync(staticPath)) {
1201
- spinner.text = "Copying `static` folder into `.react-email/public/static`";
1202
- const builtStaticDirectory = path10.resolve(
1203
- builtPreviewAppPath,
1204
- "./public/static"
1205
- );
1206
- await fs8.promises.cp(staticPath, builtStaticDirectory, {
1207
- recursive: true
1208
- });
1209
- }
1210
- spinner.text = "Setting Next environment variables for preview app to work properly";
1211
- await setNextEnvironmentVariablesForBuild(
1212
- emailsDirRelativePath,
1213
- builtPreviewAppPath
1214
- );
1215
- spinner.text = "Setting server side generation for the email preview pages";
1216
- await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
1217
- spinner.text = "Updating package.json's build and start scripts";
1218
- await updatePackageJson(builtPreviewAppPath);
1219
- spinner.text = "Installing dependencies on `.react-email`";
1220
- await npmInstall(builtPreviewAppPath, packageManager);
1221
- spinner.stopAndPersist({
1222
- text: "Successfully prepared `.react-email` for `next build`",
1223
- symbol: logSymbols4.success
1224
- });
1225
- await buildPreviewApp(builtPreviewAppPath);
1226
- } catch (error) {
1227
- console.log(error);
1228
- process.exit(1);
1229
- }
1230
- };
1231
-
1232
1221
  // src/cli/commands/start.ts
1222
+ import { spawn as spawn2 } from "node:child_process";
1233
1223
  import fs9 from "node:fs";
1234
1224
  import path11 from "node:path";
1235
- import { spawn as spawn2 } from "node:child_process";
1236
1225
  var start = async () => {
1237
1226
  try {
1238
1227
  const usersProjectLocation = process.cwd();
@@ -1270,7 +1259,7 @@ program.command("build").description("Copies the preview app for onto .react-ema
1270
1259
  "-p --packageManager <name>",
1271
1260
  "Package name to use on installation on `.react-email`",
1272
1261
  "npm"
1273
- ).action(build2);
1262
+ ).action(build);
1274
1263
  program.command("start").description('Runs the built preview app that is inside of ".react-email"').action(start);
1275
1264
  program.command("export").description("Build the templates to the `out` directory").option("--outDir <path>", "Output directory", "out").option("-p, --pretty", "Pretty print the output", false).option("-t, --plainText", "Set output format as plain text", false).option("-d, --dir <path>", "Directory with your email templates", "./emails").option(
1276
1265
  "-s, --silent",