react-email 4.1.0-canary.8 → 4.1.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.
- package/CHANGELOG.md +44 -0
- package/dev/CHANGELOG.md +3 -0
- package/dev/index.js +44 -0
- package/dev/package.json +13 -0
- package/dist/cli/index.mjs +1391 -0
- package/dist/index.js +378 -366
- package/dist/preview/.next/BUILD_ID +1 -0
- package/dist/preview/.next/app-build-manifest.json +44 -0
- package/dist/preview/.next/app-path-routes-manifest.json +6 -0
- package/dist/preview/.next/build-manifest.json +33 -0
- package/dist/preview/.next/diagnostics/build-diagnostics.json +6 -0
- package/dist/preview/.next/diagnostics/framework.json +1 -0
- package/dist/preview/.next/export-marker.json +6 -0
- package/dist/preview/.next/images-manifest.json +57 -0
- package/dist/preview/.next/next-minimal-server.js.nft.json +1 -0
- package/dist/preview/.next/next-server.js.nft.json +1 -0
- package/dist/preview/.next/package.json +1 -0
- package/dist/preview/.next/prerender-manifest.json +41 -0
- package/dist/preview/.next/react-loadable-manifest.json +1 -0
- package/dist/preview/.next/required-server-files.json +311 -0
- package/dist/preview/.next/routes-manifest.json +64 -0
- package/dist/preview/.next/server/app/_not-found/page.js +1 -0
- package/dist/preview/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/preview/.next/server/app/favicon.ico/route.js +1 -0
- package/dist/preview/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/dist/preview/.next/server/app/favicon.ico.body +0 -0
- package/dist/preview/.next/server/app/favicon.ico.meta +1 -0
- package/dist/preview/.next/server/app/page.js +1 -0
- package/dist/preview/.next/server/app/page.js.nft.json +1 -0
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/preview/.next/server/app/preview/[...slug]/page.js +321 -0
- package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -0
- package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -0
- package/dist/preview/.next/server/app-paths-manifest.json +6 -0
- package/dist/preview/.next/server/chunks/134.js +6 -0
- package/dist/preview/.next/server/chunks/235.js +15 -0
- package/dist/preview/.next/server/chunks/343.js +20 -0
- package/dist/preview/.next/server/chunks/428.js +14 -0
- package/dist/preview/.next/server/chunks/934.js +1 -0
- package/dist/preview/.next/server/chunks/963.js +1 -0
- package/dist/preview/.next/server/functions-config-manifest.json +4 -0
- package/dist/preview/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/dist/preview/.next/server/middleware-build-manifest.js +1 -0
- package/dist/preview/.next/server/middleware-manifest.json +6 -0
- package/dist/preview/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/preview/.next/server/next-font-manifest.js +1 -0
- package/dist/preview/.next/server/next-font-manifest.json +1 -0
- package/dist/preview/.next/server/pages/500.html +1 -0
- package/dist/preview/.next/server/pages/_app.js +1 -0
- package/dist/preview/.next/server/pages/_app.js.nft.json +1 -0
- package/dist/preview/.next/server/pages/_document.js +1 -0
- package/dist/preview/.next/server/pages/_document.js.nft.json +1 -0
- package/dist/preview/.next/server/pages/_error.js +1 -0
- package/dist/preview/.next/server/pages/_error.js.nft.json +1 -0
- package/dist/preview/.next/server/pages-manifest.json +5 -0
- package/dist/preview/.next/server/server-reference-manifest.js +1 -0
- package/dist/preview/.next/server/server-reference-manifest.json +1 -0
- package/dist/preview/.next/server/webpack-runtime.js +1 -0
- package/dist/preview/.next/static/FZEE-q531kq1Juxsda2po/_buildManifest.js +1 -0
- package/dist/preview/.next/static/FZEE-q531kq1Juxsda2po/_ssgManifest.js +1 -0
- package/dist/preview/.next/static/chunks/107-3043079e7cb8bcae.js +1 -0
- package/dist/preview/.next/static/chunks/293-297b1eb2241f9a70.js +1 -0
- package/dist/preview/.next/static/chunks/3bd82e28-cda2c00a924937c5.js +1 -0
- package/dist/preview/.next/static/chunks/45-1021fac82f766268.js +1 -0
- package/dist/preview/.next/static/chunks/484-f5954e7b4b93f109.js +1 -0
- package/dist/preview/.next/static/chunks/589-817d8691661d370e.js +1 -0
- package/dist/preview/.next/static/chunks/902-c34acb56733e0ce1.js +1 -0
- package/dist/preview/.next/static/chunks/app/_not-found/page-4cbc7dce3ad33336.js +1 -0
- package/dist/preview/.next/static/chunks/app/layout-89c12abbc616c3a1.js +1 -0
- package/dist/preview/.next/static/chunks/app/page-0492cd9ce15b7980.js +1 -0
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-c670410568d530db.js +1 -0
- package/dist/preview/.next/static/chunks/f33a14d2-ec7c5f0b91818561.js +6 -0
- package/dist/preview/.next/static/chunks/framework-b887e9fc751a9906.js +1 -0
- package/dist/preview/.next/static/chunks/main-9a03e7ba8acb1900.js +1 -0
- package/dist/preview/.next/static/chunks/main-app-951f948d1c44189f.js +1 -0
- package/dist/preview/.next/static/chunks/pages/_app-542a93a5a214e1c0.js +1 -0
- package/dist/preview/.next/static/chunks/pages/_error-d5fe1b1612642f76.js +1 -0
- package/dist/preview/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/preview/.next/static/chunks/webpack-31c45daa2bd82a7b.js +1 -0
- package/dist/preview/.next/static/css/78c81281aa95270f.css +3 -0
- package/dist/preview/.next/static/media/05613964ce6c782e-s.p.otf +0 -0
- package/dist/preview/.next/static/media/11c6126b9369e85e-s.p.otf +0 -0
- package/dist/preview/.next/static/media/26a46d62cd723877-s.woff2 +0 -0
- package/dist/preview/.next/static/media/26cb97734d8cb717-s.p.otf +0 -0
- package/dist/preview/.next/static/media/55c55f0601d81cf3-s.woff2 +0 -0
- package/dist/preview/.next/static/media/581909926a08bbc8-s.woff2 +0 -0
- package/dist/preview/.next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
- package/dist/preview/.next/static/media/97e0cb1ae144a2a9-s.woff2 +0 -0
- package/dist/preview/.next/static/media/bb6462617151f6b7-s.p.otf +0 -0
- package/dist/preview/.next/static/media/cf6daef822ab0142-s.p.otf +0 -0
- package/dist/preview/.next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
- package/dist/preview/.next/static/media/e4051546b3043204-s.p.otf +0 -0
- package/dist/preview/.next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
- package/dist/preview/.next/static/media/logo.2ce2a759.png +0 -0
- package/dist/preview/.next/trace +27 -0
- package/dist/preview/.next/types/app/layout.ts +84 -0
- package/dist/preview/.next/types/app/page.ts +84 -0
- package/dist/preview/.next/types/app/preview/[...slug]/page.ts +84 -0
- package/dist/preview/.next/types/cache-life.d.ts +141 -0
- package/dist/preview/.next/types/package.json +1 -0
- package/package.json +4 -4
- package/readme.md +16 -0
- package/src/actions/email-validation/__snapshots__/check-images.spec.tsx.snap +84 -0
- package/src/utils/get-preview-server-location.ts +34 -15
- package/src/utils/preview/get-env-variables-for-preview-app.ts +0 -2
- package/src/utils/preview/hot-reloading/create-dependency-graph.spec.ts +1 -70
- package/src/utils/preview/hot-reloading/create-dependency-graph.ts +2 -5
- package/src/utils/preview/serve-static-file.ts +2 -1
- package/src/utils/preview/start-dev-server.ts +1 -6
package/dist/index.js
CHANGED
|
@@ -102,6 +102,88 @@ import url from "node:url";
|
|
|
102
102
|
import { createJiti } from "jiti";
|
|
103
103
|
import { addDevDependency } from "nypm";
|
|
104
104
|
import prompts from "prompts";
|
|
105
|
+
|
|
106
|
+
// package.json
|
|
107
|
+
var package_default = {
|
|
108
|
+
name: "react-email",
|
|
109
|
+
version: "4.1.0",
|
|
110
|
+
description: "A live preview of your emails right in your browser.",
|
|
111
|
+
bin: {
|
|
112
|
+
email: "./dist/index.js"
|
|
113
|
+
},
|
|
114
|
+
type: "module",
|
|
115
|
+
scripts: {
|
|
116
|
+
build: "tsup-node",
|
|
117
|
+
"build:watch": "tsup-node --watch src",
|
|
118
|
+
clean: "rm -rf dist",
|
|
119
|
+
test: "vitest run",
|
|
120
|
+
"test:watch": "vitest"
|
|
121
|
+
},
|
|
122
|
+
license: "MIT",
|
|
123
|
+
repository: {
|
|
124
|
+
type: "git",
|
|
125
|
+
url: "https://github.com/resend/react-email.git",
|
|
126
|
+
directory: "packages/react-email"
|
|
127
|
+
},
|
|
128
|
+
keywords: [
|
|
129
|
+
"react",
|
|
130
|
+
"email"
|
|
131
|
+
],
|
|
132
|
+
engines: {
|
|
133
|
+
node: ">=18.0.0"
|
|
134
|
+
},
|
|
135
|
+
dependencies: {
|
|
136
|
+
"@babel/parser": "^7.27.0",
|
|
137
|
+
"@babel/traverse": "^7.27.0",
|
|
138
|
+
chalk: "^5.0.0",
|
|
139
|
+
chokidar: "^4.0.3",
|
|
140
|
+
commander: "^13.0.0",
|
|
141
|
+
debounce: "^2.0.0",
|
|
142
|
+
esbuild: "^0.25.0",
|
|
143
|
+
glob: "^11.0.0",
|
|
144
|
+
jiti: "2.4.2",
|
|
145
|
+
"log-symbols": "^7.0.0",
|
|
146
|
+
"mime-types": "^3.0.0",
|
|
147
|
+
"normalize-path": "^3.0.0",
|
|
148
|
+
nypm: "0.6.0",
|
|
149
|
+
ora: "^8.0.0",
|
|
150
|
+
prompts: "2.4.2",
|
|
151
|
+
"socket.io": "^4.8.1",
|
|
152
|
+
"tsconfig-paths": "4.2.0"
|
|
153
|
+
},
|
|
154
|
+
devDependencies: {
|
|
155
|
+
"@react-email/components": "workspace:*",
|
|
156
|
+
"@types/babel__core": "7.20.5",
|
|
157
|
+
"@types/babel__traverse": "7.20.7",
|
|
158
|
+
"@types/mime-types": "2.1.4",
|
|
159
|
+
"@types/prompts": "2.4.9",
|
|
160
|
+
next: "^15.3.2",
|
|
161
|
+
react: "19.0.0",
|
|
162
|
+
"react-dom": "19.0.0",
|
|
163
|
+
tsup: "8.4.0",
|
|
164
|
+
tsx: "4.19.3",
|
|
165
|
+
typescript: "5.8.3"
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/utils/get-preview-server-location.ts
|
|
170
|
+
var ensurePreviewServerInstalled = async (message) => {
|
|
171
|
+
const response = await prompts({
|
|
172
|
+
type: "confirm",
|
|
173
|
+
name: "installPreviewServer",
|
|
174
|
+
message,
|
|
175
|
+
initial: true
|
|
176
|
+
});
|
|
177
|
+
if (response.installPreviewServer) {
|
|
178
|
+
console.log('Installing "@react-email/preview-server"');
|
|
179
|
+
await addDevDependency(
|
|
180
|
+
`@react-email/preview-server@${package_default.version}`
|
|
181
|
+
);
|
|
182
|
+
process.exit(0);
|
|
183
|
+
} else {
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
105
187
|
var getPreviewServerLocation = async () => {
|
|
106
188
|
const usersProject = createJiti(process.cwd());
|
|
107
189
|
let previewServerLocation;
|
|
@@ -109,20 +191,16 @@ var getPreviewServerLocation = async () => {
|
|
|
109
191
|
previewServerLocation = path2.dirname(
|
|
110
192
|
url.parse(usersProject.esmResolve("@react-email/preview-server"), true).path
|
|
111
193
|
);
|
|
112
|
-
} catch (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
process.exit(0);
|
|
123
|
-
} else {
|
|
124
|
-
process.exit(0);
|
|
125
|
-
}
|
|
194
|
+
} catch (_exception) {
|
|
195
|
+
await ensurePreviewServerInstalled(
|
|
196
|
+
'To run the preview server, the package "@react-email/preview-server" must be installed. Would you like to install it?'
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
const { version } = await usersProject.import("@react-email/preview-server");
|
|
200
|
+
if (version !== package_default.version) {
|
|
201
|
+
await ensurePreviewServerInstalled(
|
|
202
|
+
`To run the preview server, the version of "@react-email/preview-server" must match the version of "react-email" (${package_default.version}). Would you like to install it?`
|
|
203
|
+
);
|
|
126
204
|
}
|
|
127
205
|
return previewServerLocation;
|
|
128
206
|
};
|
|
@@ -248,8 +326,8 @@ var getEmailSlugsFromEmailDirectory = (emailDirectory, emailsDirectoryAbsolutePa
|
|
|
248
326
|
const directoryPathRelativeToEmailsDirectory = emailDirectory.absolutePath.replace(emailsDirectoryAbsolutePath, "").trim();
|
|
249
327
|
const slugs = [];
|
|
250
328
|
emailDirectory.emailFilenames.forEach(
|
|
251
|
-
(
|
|
252
|
-
path3.join(directoryPathRelativeToEmailsDirectory,
|
|
329
|
+
(filename2) => slugs.push(
|
|
330
|
+
path3.join(directoryPathRelativeToEmailsDirectory, filename2).split(path3.sep).filter((segment) => segment.length > 0)
|
|
253
331
|
)
|
|
254
332
|
);
|
|
255
333
|
emailDirectory.subDirectories.forEach((directory) => {
|
|
@@ -352,325 +430,42 @@ var build = async ({
|
|
|
352
430
|
);
|
|
353
431
|
await fs2.promises.cp(staticPath, builtStaticDirectory, {
|
|
354
432
|
recursive: true
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
spinner.text = "Setting Next environment variables for preview app to work properly";
|
|
358
|
-
await setNextEnvironmentVariablesForBuild(
|
|
359
|
-
emailsDirRelativePath,
|
|
360
|
-
builtPreviewAppPath
|
|
361
|
-
);
|
|
362
|
-
spinner.text = "Setting server side generation for the email preview pages";
|
|
363
|
-
await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
|
|
364
|
-
spinner.text = "Updating package.json's build and start scripts";
|
|
365
|
-
await updatePackageJson(builtPreviewAppPath);
|
|
366
|
-
spinner.text = "Installing dependencies on `.react-email`";
|
|
367
|
-
await npmInstall(builtPreviewAppPath, packageManager);
|
|
368
|
-
spinner.stopAndPersist({
|
|
369
|
-
text: "Successfully prepared `.react-email` for `next build`",
|
|
370
|
-
symbol: logSymbols2.success
|
|
371
|
-
});
|
|
372
|
-
await buildPreviewApp(builtPreviewAppPath);
|
|
373
|
-
} catch (error) {
|
|
374
|
-
console.log(error);
|
|
375
|
-
process.exit(1);
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
// src/commands/dev.ts
|
|
380
|
-
import fs6 from "node:fs";
|
|
381
|
-
|
|
382
|
-
// src/utils/preview/hot-reloading/setup-hot-reloading.ts
|
|
383
|
-
import path9 from "node:path";
|
|
384
|
-
import { watch } from "chokidar";
|
|
385
|
-
import debounce from "debounce";
|
|
386
|
-
import { Server as SocketServer } from "socket.io";
|
|
387
|
-
|
|
388
|
-
// src/utils/preview/hot-reloading/create-dependency-graph.ts
|
|
389
|
-
import { existsSync as existsSync2, promises as fs4, statSync } from "node:fs";
|
|
390
|
-
import path8 from "node:path";
|
|
391
|
-
|
|
392
|
-
// src/utils/preview/start-dev-server.ts
|
|
393
|
-
import http from "node:http";
|
|
394
|
-
import path6 from "node:path";
|
|
395
|
-
import url2 from "node:url";
|
|
396
|
-
import chalk from "chalk";
|
|
397
|
-
import { createJiti as createJiti2 } from "jiti";
|
|
398
|
-
import logSymbols3 from "log-symbols";
|
|
399
|
-
import ora2 from "ora";
|
|
400
|
-
|
|
401
|
-
// package.json
|
|
402
|
-
var package_default = {
|
|
403
|
-
name: "react-email",
|
|
404
|
-
version: "4.1.0-canary.8",
|
|
405
|
-
description: "A live preview of your emails right in your browser.",
|
|
406
|
-
bin: {
|
|
407
|
-
email: "./dist/index.js"
|
|
408
|
-
},
|
|
409
|
-
type: "module",
|
|
410
|
-
scripts: {
|
|
411
|
-
build: "tsup-node",
|
|
412
|
-
clean: "rm -rf dist",
|
|
413
|
-
dev: "tsup-node --watch src",
|
|
414
|
-
test: "vitest run",
|
|
415
|
-
"test:watch": "vitest"
|
|
416
|
-
},
|
|
417
|
-
license: "MIT",
|
|
418
|
-
repository: {
|
|
419
|
-
type: "git",
|
|
420
|
-
url: "https://github.com/resend/react-email.git",
|
|
421
|
-
directory: "packages/react-email"
|
|
422
|
-
},
|
|
423
|
-
keywords: [
|
|
424
|
-
"react",
|
|
425
|
-
"email"
|
|
426
|
-
],
|
|
427
|
-
engines: {
|
|
428
|
-
node: ">=18.0.0"
|
|
429
|
-
},
|
|
430
|
-
dependencies: {
|
|
431
|
-
"@babel/parser": "^7.27.0",
|
|
432
|
-
"@babel/traverse": "^7.27.0",
|
|
433
|
-
chalk: "^5.0.0",
|
|
434
|
-
chokidar: "^4.0.3",
|
|
435
|
-
commander: "^13.0.0",
|
|
436
|
-
debounce: "^2.0.0",
|
|
437
|
-
esbuild: "^0.25.0",
|
|
438
|
-
glob: "^11.0.0",
|
|
439
|
-
jiti: "2.4.2",
|
|
440
|
-
"log-symbols": "^7.0.0",
|
|
441
|
-
"mime-types": "^3.0.0",
|
|
442
|
-
"normalize-path": "^3.0.0",
|
|
443
|
-
nypm: "0.6.0",
|
|
444
|
-
ora: "^8.0.0",
|
|
445
|
-
prompts: "2.4.2",
|
|
446
|
-
"socket.io": "^4.8.1",
|
|
447
|
-
"tsconfig-paths": "4.2.0"
|
|
448
|
-
},
|
|
449
|
-
devDependencies: {
|
|
450
|
-
"@react-email/components": "workspace:*",
|
|
451
|
-
"@types/babel__core": "7.20.5",
|
|
452
|
-
"@types/babel__traverse": "7.20.7",
|
|
453
|
-
"@types/mime-types": "2.1.4",
|
|
454
|
-
"@types/prompts": "2.4.9",
|
|
455
|
-
next: "^15.3.1",
|
|
456
|
-
react: "19.0.0",
|
|
457
|
-
"react-dom": "19.0.0",
|
|
458
|
-
tsup: "8.4.0",
|
|
459
|
-
tsx: "4.19.3",
|
|
460
|
-
typescript: "5.8.3"
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
// src/utils/preview/get-env-variables-for-preview-app.ts
|
|
465
|
-
import path4 from "node:path";
|
|
466
|
-
var getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, cwd) => {
|
|
467
|
-
return {
|
|
468
|
-
EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
|
|
469
|
-
EMAILS_DIR_ABSOLUTE_PATH: path4.resolve(cwd, relativePathToEmailsDirectory),
|
|
470
|
-
USER_PROJECT_LOCATION: cwd,
|
|
471
|
-
NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
|
|
472
|
-
};
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
// src/utils/preview/serve-static-file.ts
|
|
476
|
-
import { existsSync, promises as fs3 } from "node:fs";
|
|
477
|
-
import path5 from "node:path";
|
|
478
|
-
import { lookup } from "mime-types";
|
|
479
|
-
var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
|
|
480
|
-
const pathname = parsedUrl.pathname.replace("/static", "./static");
|
|
481
|
-
const ext = path5.parse(pathname).ext;
|
|
482
|
-
const staticBaseDir = path5.resolve(process.cwd(), staticDirRelativePath);
|
|
483
|
-
const fileAbsolutePath = path5.resolve(staticBaseDir, pathname);
|
|
484
|
-
if (!fileAbsolutePath.startsWith(staticBaseDir)) {
|
|
485
|
-
res.statusCode = 403;
|
|
486
|
-
res.end();
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
try {
|
|
490
|
-
const fileHandle = await fs3.open(fileAbsolutePath, "r");
|
|
491
|
-
const fileData = await fs3.readFile(fileHandle);
|
|
492
|
-
res.setHeader("Content-type", lookup(ext) || "text/plain");
|
|
493
|
-
res.end(fileData);
|
|
494
|
-
fileHandle.close();
|
|
495
|
-
} catch (exception) {
|
|
496
|
-
if (!existsSync(fileAbsolutePath)) {
|
|
497
|
-
res.statusCode = 404;
|
|
498
|
-
res.end();
|
|
499
|
-
} else {
|
|
500
|
-
const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
|
|
501
|
-
console.error(
|
|
502
|
-
`Could not read file at ${sanitizedFilePath} to be served, here's the exception:`,
|
|
503
|
-
exception
|
|
504
|
-
);
|
|
505
|
-
res.statusCode = 500;
|
|
506
|
-
res.end(
|
|
507
|
-
"Could not read file to be served! Check your terminal for more information."
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
// src/utils/preview/start-dev-server.ts
|
|
514
|
-
var devServer;
|
|
515
|
-
var safeAsyncServerListen = (server, port) => {
|
|
516
|
-
return new Promise((resolve) => {
|
|
517
|
-
server.listen(port, () => {
|
|
518
|
-
resolve({ portAlreadyInUse: false });
|
|
519
|
-
});
|
|
520
|
-
server.on("error", (e) => {
|
|
521
|
-
if (e.code === "EADDRINUSE") {
|
|
522
|
-
resolve({ portAlreadyInUse: true });
|
|
523
|
-
}
|
|
524
|
-
});
|
|
525
|
-
});
|
|
526
|
-
};
|
|
527
|
-
var filename = url2.fileURLToPath(import.meta.url);
|
|
528
|
-
var dirname = path6.dirname(filename);
|
|
529
|
-
var isDev = !dirname.includes("dist");
|
|
530
|
-
var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
|
|
531
|
-
const [majorNodeVersion] = process.versions.node.split(".");
|
|
532
|
-
if (majorNodeVersion && Number.parseInt(majorNodeVersion) < 18) {
|
|
533
|
-
console.error(
|
|
534
|
-
` ${logSymbols3.error} Node ${majorNodeVersion} is not supported. Please upgrade to Node 18 or higher.`
|
|
535
|
-
);
|
|
536
|
-
process.exit(1);
|
|
537
|
-
}
|
|
538
|
-
const previewServerLocation = await getPreviewServerLocation();
|
|
539
|
-
const previewServer = createJiti2(previewServerLocation);
|
|
540
|
-
const { default: next } = await previewServer.import("next");
|
|
541
|
-
devServer = http.createServer((req, res) => {
|
|
542
|
-
if (!req.url) {
|
|
543
|
-
res.end(404);
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
const parsedUrl = url2.parse(req.url, true);
|
|
547
|
-
res.setHeader(
|
|
548
|
-
"Cache-Control",
|
|
549
|
-
"no-cache, max-age=0, must-revalidate, no-store"
|
|
550
|
-
);
|
|
551
|
-
res.setHeader("Pragma", "no-cache");
|
|
552
|
-
res.setHeader("Expires", "-1");
|
|
553
|
-
try {
|
|
554
|
-
if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) {
|
|
555
|
-
void serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
|
|
556
|
-
} else if (!isNextReady) {
|
|
557
|
-
void nextReadyPromise.then(
|
|
558
|
-
() => nextHandleRequest?.(req, res, parsedUrl)
|
|
559
|
-
);
|
|
560
|
-
} else {
|
|
561
|
-
void nextHandleRequest?.(req, res, parsedUrl);
|
|
562
|
-
}
|
|
563
|
-
} catch (e) {
|
|
564
|
-
console.error("caught error", e);
|
|
565
|
-
res.writeHead(500);
|
|
566
|
-
res.end();
|
|
567
|
-
}
|
|
568
|
-
});
|
|
569
|
-
const { portAlreadyInUse } = await safeAsyncServerListen(devServer, port);
|
|
570
|
-
if (!portAlreadyInUse) {
|
|
571
|
-
console.log(chalk.greenBright(` React Email ${package_default.version}`));
|
|
572
|
-
console.log(` Running preview at: http://localhost:${port}
|
|
573
|
-
`);
|
|
574
|
-
} else {
|
|
575
|
-
const nextPortToTry = port + 1;
|
|
576
|
-
console.warn(
|
|
577
|
-
` ${logSymbols3.warning} Port ${port} is already in use, trying ${nextPortToTry}`
|
|
578
|
-
);
|
|
579
|
-
return startDevServer(
|
|
580
|
-
emailsDirRelativePath,
|
|
581
|
-
staticBaseDirRelativePath,
|
|
582
|
-
nextPortToTry
|
|
583
|
-
);
|
|
584
|
-
}
|
|
585
|
-
devServer.on("close", async () => {
|
|
586
|
-
await app.close();
|
|
587
|
-
});
|
|
588
|
-
devServer.on("error", (e) => {
|
|
589
|
-
spinner.stopAndPersist({
|
|
590
|
-
symbol: logSymbols3.error,
|
|
591
|
-
text: `Preview Server had an error: ${e}`
|
|
592
|
-
});
|
|
593
|
-
process.exit(1);
|
|
594
|
-
});
|
|
595
|
-
const spinner = ora2({
|
|
596
|
-
text: "Getting react-email preview server ready...\n",
|
|
597
|
-
prefixText: " "
|
|
598
|
-
}).start();
|
|
599
|
-
registerSpinnerAutostopping(spinner);
|
|
600
|
-
const timeBeforeNextReady = performance.now();
|
|
601
|
-
process.env = {
|
|
602
|
-
NODE_ENV: "development",
|
|
603
|
-
...process.env,
|
|
604
|
-
...getEnvVariablesForPreviewApp(
|
|
605
|
-
// If we don't do normalization here, stuff like https://github.com/resend/react-email/issues/1354 happens.
|
|
606
|
-
path6.normalize(emailsDirRelativePath),
|
|
607
|
-
process.cwd()
|
|
608
|
-
)
|
|
609
|
-
};
|
|
610
|
-
const app = next({
|
|
611
|
-
// passing in env here does not get the environment variables there
|
|
612
|
-
dev: isDev,
|
|
613
|
-
conf: {
|
|
614
|
-
images: {
|
|
615
|
-
// This is to avoid the warning with sharp
|
|
616
|
-
unoptimized: true
|
|
617
|
-
}
|
|
618
|
-
},
|
|
619
|
-
hostname: "localhost",
|
|
620
|
-
port,
|
|
621
|
-
dir: previewServerLocation
|
|
622
|
-
});
|
|
623
|
-
let isNextReady = false;
|
|
624
|
-
const nextReadyPromise = app.prepare();
|
|
625
|
-
try {
|
|
626
|
-
await nextReadyPromise;
|
|
627
|
-
} catch (exception) {
|
|
628
|
-
spinner.stopAndPersist({
|
|
629
|
-
symbol: logSymbols3.error,
|
|
630
|
-
text: ` Preview Server had an error: ${exception}`
|
|
631
|
-
});
|
|
632
|
-
process.exit(1);
|
|
633
|
-
}
|
|
634
|
-
isNextReady = true;
|
|
635
|
-
const nextHandleRequest = app.getRequestHandler();
|
|
636
|
-
const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
|
|
637
|
-
spinner.stopAndPersist({
|
|
638
|
-
text: `Ready in ${secondsToNextReady}s
|
|
639
|
-
`,
|
|
640
|
-
symbol: logSymbols3.success
|
|
641
|
-
});
|
|
642
|
-
return devServer;
|
|
643
|
-
};
|
|
644
|
-
var makeExitHandler = (options) => (codeSignalOrError) => {
|
|
645
|
-
if (typeof devServer !== "undefined") {
|
|
646
|
-
console.log("\nshutting down dev server");
|
|
647
|
-
devServer.close();
|
|
648
|
-
devServer = void 0;
|
|
649
|
-
}
|
|
650
|
-
if (codeSignalOrError instanceof Error) {
|
|
651
|
-
console.error(codeSignalOrError);
|
|
652
|
-
}
|
|
653
|
-
if (options?.shouldKillProcess) {
|
|
654
|
-
process.exit(options.killWithErrorCode ? 1 : 0);
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
spinner.text = "Setting Next environment variables for preview app to work properly";
|
|
436
|
+
await setNextEnvironmentVariablesForBuild(
|
|
437
|
+
emailsDirRelativePath,
|
|
438
|
+
builtPreviewAppPath
|
|
439
|
+
);
|
|
440
|
+
spinner.text = "Setting server side generation for the email preview pages";
|
|
441
|
+
await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
|
|
442
|
+
spinner.text = "Updating package.json's build and start scripts";
|
|
443
|
+
await updatePackageJson(builtPreviewAppPath);
|
|
444
|
+
spinner.text = "Installing dependencies on `.react-email`";
|
|
445
|
+
await npmInstall(builtPreviewAppPath, packageManager);
|
|
446
|
+
spinner.stopAndPersist({
|
|
447
|
+
text: "Successfully prepared `.react-email` for `next build`",
|
|
448
|
+
symbol: logSymbols2.success
|
|
449
|
+
});
|
|
450
|
+
await buildPreviewApp(builtPreviewAppPath);
|
|
451
|
+
} catch (error) {
|
|
452
|
+
console.log(error);
|
|
453
|
+
process.exit(1);
|
|
655
454
|
}
|
|
656
455
|
};
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
process.on(
|
|
671
|
-
"uncaughtException",
|
|
672
|
-
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
|
|
673
|
-
);
|
|
456
|
+
|
|
457
|
+
// src/commands/dev.ts
|
|
458
|
+
import fs6 from "node:fs";
|
|
459
|
+
|
|
460
|
+
// src/utils/preview/hot-reloading/setup-hot-reloading.ts
|
|
461
|
+
import path6 from "node:path";
|
|
462
|
+
import { watch } from "chokidar";
|
|
463
|
+
import debounce from "debounce";
|
|
464
|
+
import { Server as SocketServer } from "socket.io";
|
|
465
|
+
|
|
466
|
+
// src/utils/preview/hot-reloading/create-dependency-graph.ts
|
|
467
|
+
import { existsSync, promises as fs3, statSync } from "node:fs";
|
|
468
|
+
import path5 from "node:path";
|
|
674
469
|
|
|
675
470
|
// src/utils/preview/hot-reloading/get-imported-modules.ts
|
|
676
471
|
import { parse } from "@babel/parser";
|
|
@@ -718,7 +513,7 @@ var getImportedModules = (contents) => {
|
|
|
718
513
|
};
|
|
719
514
|
|
|
720
515
|
// src/utils/preview/hot-reloading/resolve-path-aliases.ts
|
|
721
|
-
import
|
|
516
|
+
import path4 from "node:path";
|
|
722
517
|
import { createMatchPath, loadConfig } from "tsconfig-paths";
|
|
723
518
|
var resolvePathAliases = (importPaths, projectPath) => {
|
|
724
519
|
const configLoadResult = loadConfig(projectPath);
|
|
@@ -737,7 +532,7 @@ var resolvePathAliases = (importPaths, projectPath) => {
|
|
|
737
532
|
".mjs"
|
|
738
533
|
]);
|
|
739
534
|
if (unaliasedPath) {
|
|
740
|
-
return `./${
|
|
535
|
+
return `./${path4.relative(projectPath, unaliasedPath)}`;
|
|
741
536
|
}
|
|
742
537
|
return importedPath;
|
|
743
538
|
});
|
|
@@ -748,9 +543,9 @@ var resolvePathAliases = (importPaths, projectPath) => {
|
|
|
748
543
|
// src/utils/preview/hot-reloading/create-dependency-graph.ts
|
|
749
544
|
var readAllFilesInsideDirectory = async (directory) => {
|
|
750
545
|
let allFilePaths = [];
|
|
751
|
-
const topLevelDirents = await
|
|
546
|
+
const topLevelDirents = await fs3.readdir(directory, { withFileTypes: true });
|
|
752
547
|
for await (const dirent of topLevelDirents) {
|
|
753
|
-
const pathToDirent =
|
|
548
|
+
const pathToDirent = path5.join(directory, dirent.name);
|
|
754
549
|
if (dirent.isDirectory()) {
|
|
755
550
|
allFilePaths = allFilePaths.concat(
|
|
756
551
|
await readAllFilesInsideDirectory(pathToDirent)
|
|
@@ -762,26 +557,26 @@ var readAllFilesInsideDirectory = async (directory) => {
|
|
|
762
557
|
return allFilePaths;
|
|
763
558
|
};
|
|
764
559
|
var isJavascriptModule = (filePath) => {
|
|
765
|
-
const extensionName =
|
|
560
|
+
const extensionName = path5.extname(filePath);
|
|
766
561
|
return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
|
|
767
562
|
};
|
|
768
563
|
var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
|
|
769
|
-
if (
|
|
564
|
+
if (existsSync(`${pathWithoutExtension}.ts`)) {
|
|
770
565
|
return `${pathWithoutExtension}.ts`;
|
|
771
566
|
}
|
|
772
|
-
if (
|
|
567
|
+
if (existsSync(`${pathWithoutExtension}.tsx`)) {
|
|
773
568
|
return `${pathWithoutExtension}.tsx`;
|
|
774
569
|
}
|
|
775
|
-
if (
|
|
570
|
+
if (existsSync(`${pathWithoutExtension}.js`)) {
|
|
776
571
|
return `${pathWithoutExtension}.js`;
|
|
777
572
|
}
|
|
778
|
-
if (
|
|
573
|
+
if (existsSync(`${pathWithoutExtension}.jsx`)) {
|
|
779
574
|
return `${pathWithoutExtension}.jsx`;
|
|
780
575
|
}
|
|
781
|
-
if (
|
|
576
|
+
if (existsSync(`${pathWithoutExtension}.mjs`)) {
|
|
782
577
|
return `${pathWithoutExtension}.mjs`;
|
|
783
578
|
}
|
|
784
|
-
if (
|
|
579
|
+
if (existsSync(`${pathWithoutExtension}.cjs`)) {
|
|
785
580
|
return `${pathWithoutExtension}.cjs`;
|
|
786
581
|
}
|
|
787
582
|
};
|
|
@@ -800,15 +595,15 @@ var createDependencyGraph = async (directory) => {
|
|
|
800
595
|
])
|
|
801
596
|
);
|
|
802
597
|
const getDependencyPaths = async (filePath) => {
|
|
803
|
-
const contents = await
|
|
804
|
-
const importedPaths = isJavascriptModule(filePath) ? resolvePathAliases(getImportedModules(contents),
|
|
598
|
+
const contents = await fs3.readFile(filePath, "utf8");
|
|
599
|
+
const importedPaths = isJavascriptModule(filePath) ? resolvePathAliases(getImportedModules(contents), path5.dirname(filePath)) : [];
|
|
805
600
|
const importedPathsRelativeToDirectory = importedPaths.map(
|
|
806
601
|
(dependencyPath) => {
|
|
807
602
|
const isModulePath = !dependencyPath.startsWith(".");
|
|
808
|
-
if (isModulePath ||
|
|
603
|
+
if (isModulePath || path5.isAbsolute(dependencyPath)) {
|
|
809
604
|
return dependencyPath;
|
|
810
605
|
}
|
|
811
|
-
let pathToDependencyFromDirectory =
|
|
606
|
+
let pathToDependencyFromDirectory = path5.resolve(
|
|
812
607
|
/*
|
|
813
608
|
path.resolve resolves paths differently from what imports on javascript do.
|
|
814
609
|
|
|
@@ -816,7 +611,7 @@ var createDependencyGraph = async (directory) => {
|
|
|
816
611
|
would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
|
|
817
612
|
one the import is meant to go to
|
|
818
613
|
*/
|
|
819
|
-
|
|
614
|
+
path5.dirname(filePath),
|
|
820
615
|
dependencyPath
|
|
821
616
|
);
|
|
822
617
|
let isDirectory = false;
|
|
@@ -831,15 +626,15 @@ var createDependencyGraph = async (directory) => {
|
|
|
831
626
|
);
|
|
832
627
|
if (pathWithExtension) {
|
|
833
628
|
pathToDependencyFromDirectory = pathWithExtension;
|
|
834
|
-
} else
|
|
629
|
+
} else {
|
|
835
630
|
console.warn(
|
|
836
631
|
`Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
|
|
837
632
|
);
|
|
838
633
|
}
|
|
839
634
|
}
|
|
840
|
-
const extension =
|
|
635
|
+
const extension = path5.extname(pathToDependencyFromDirectory);
|
|
841
636
|
const pathWithEnsuredExtension = (() => {
|
|
842
|
-
if (extension.length > 0 &&
|
|
637
|
+
if (extension.length > 0 && existsSync(pathToDependencyFromDirectory)) {
|
|
843
638
|
return pathToDependencyFromDirectory;
|
|
844
639
|
}
|
|
845
640
|
return checkFileExtensionsUntilItExists(
|
|
@@ -848,7 +643,7 @@ var createDependencyGraph = async (directory) => {
|
|
|
848
643
|
})();
|
|
849
644
|
if (pathWithEnsuredExtension) {
|
|
850
645
|
pathToDependencyFromDirectory = pathWithEnsuredExtension;
|
|
851
|
-
} else
|
|
646
|
+
} else {
|
|
852
647
|
console.warn(
|
|
853
648
|
`Could not find file at ${pathToDependencyFromDirectory}`
|
|
854
649
|
);
|
|
@@ -857,10 +652,10 @@ var createDependencyGraph = async (directory) => {
|
|
|
857
652
|
}
|
|
858
653
|
);
|
|
859
654
|
const moduleDependencies = importedPathsRelativeToDirectory.filter(
|
|
860
|
-
(dependencyPath) => !dependencyPath.startsWith(".") && !
|
|
655
|
+
(dependencyPath) => !dependencyPath.startsWith(".") && !path5.isAbsolute(dependencyPath)
|
|
861
656
|
);
|
|
862
657
|
const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
|
|
863
|
-
(dependencyPath) => dependencyPath.startsWith(".") ||
|
|
658
|
+
(dependencyPath) => dependencyPath.startsWith(".") || path5.isAbsolute(dependencyPath)
|
|
864
659
|
);
|
|
865
660
|
return {
|
|
866
661
|
dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
|
|
@@ -991,14 +786,14 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
991
786
|
changes.filter(
|
|
992
787
|
(change) => (
|
|
993
788
|
// Ensures only changes inside the emails directory are emitted
|
|
994
|
-
|
|
789
|
+
path6.resolve(absolutePathToEmailsDirectory, change.filename).startsWith(absolutePathToEmailsDirectory)
|
|
995
790
|
)
|
|
996
791
|
)
|
|
997
792
|
);
|
|
998
793
|
});
|
|
999
794
|
changes = [];
|
|
1000
795
|
}, 150);
|
|
1001
|
-
const absolutePathToEmailsDirectory =
|
|
796
|
+
const absolutePathToEmailsDirectory = path6.resolve(
|
|
1002
797
|
process.cwd(),
|
|
1003
798
|
emailDirRelativePath
|
|
1004
799
|
);
|
|
@@ -1008,7 +803,7 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
1008
803
|
cwd: absolutePathToEmailsDirectory
|
|
1009
804
|
});
|
|
1010
805
|
const getFilesOutsideEmailsDirectory = () => Object.keys(dependencyGraph).filter(
|
|
1011
|
-
(p) =>
|
|
806
|
+
(p) => path6.relative(absolutePathToEmailsDirectory, p).startsWith("..")
|
|
1012
807
|
);
|
|
1013
808
|
let filesOutsideEmailsDirectory = getFilesOutsideEmailsDirectory();
|
|
1014
809
|
for (const p of filesOutsideEmailsDirectory) {
|
|
@@ -1020,11 +815,11 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
1020
815
|
process.on("SIGINT", exit);
|
|
1021
816
|
process.on("uncaughtException", exit);
|
|
1022
817
|
watcher.on("all", async (event, relativePathToChangeTarget) => {
|
|
1023
|
-
const file = relativePathToChangeTarget.split(
|
|
818
|
+
const file = relativePathToChangeTarget.split(path6.sep);
|
|
1024
819
|
if (file.length === 0) {
|
|
1025
820
|
return;
|
|
1026
821
|
}
|
|
1027
|
-
const pathToChangeTarget =
|
|
822
|
+
const pathToChangeTarget = path6.resolve(
|
|
1028
823
|
absolutePathToEmailsDirectory,
|
|
1029
824
|
relativePathToChangeTarget
|
|
1030
825
|
);
|
|
@@ -1048,7 +843,7 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
1048
843
|
for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
|
|
1049
844
|
changes.push({
|
|
1050
845
|
event: "change",
|
|
1051
|
-
filename:
|
|
846
|
+
filename: path6.relative(absolutePathToEmailsDirectory, dependentPath)
|
|
1052
847
|
});
|
|
1053
848
|
}
|
|
1054
849
|
reload();
|
|
@@ -1056,6 +851,223 @@ var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
|
1056
851
|
return watcher;
|
|
1057
852
|
};
|
|
1058
853
|
|
|
854
|
+
// src/utils/preview/start-dev-server.ts
|
|
855
|
+
import http from "node:http";
|
|
856
|
+
import path9 from "node:path";
|
|
857
|
+
import url2 from "node:url";
|
|
858
|
+
import chalk from "chalk";
|
|
859
|
+
import { createJiti as createJiti2 } from "jiti";
|
|
860
|
+
import logSymbols3 from "log-symbols";
|
|
861
|
+
import ora2 from "ora";
|
|
862
|
+
|
|
863
|
+
// src/utils/preview/get-env-variables-for-preview-app.ts
|
|
864
|
+
import path7 from "node:path";
|
|
865
|
+
var getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, cwd) => {
|
|
866
|
+
return {
|
|
867
|
+
EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
|
|
868
|
+
EMAILS_DIR_ABSOLUTE_PATH: path7.resolve(cwd, relativePathToEmailsDirectory),
|
|
869
|
+
USER_PROJECT_LOCATION: cwd
|
|
870
|
+
};
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
// src/utils/preview/serve-static-file.ts
|
|
874
|
+
import { existsSync as existsSync2, promises as fs4 } from "node:fs";
|
|
875
|
+
import path8 from "node:path";
|
|
876
|
+
import { lookup } from "mime-types";
|
|
877
|
+
var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
|
|
878
|
+
const pathname = parsedUrl.pathname.replace("/static", "./static");
|
|
879
|
+
const ext = path8.parse(pathname).ext;
|
|
880
|
+
const staticBaseDir = path8.resolve(process.cwd(), staticDirRelativePath);
|
|
881
|
+
const fileAbsolutePath = path8.resolve(staticBaseDir, pathname);
|
|
882
|
+
if (!fileAbsolutePath.startsWith(staticBaseDir)) {
|
|
883
|
+
res.statusCode = 403;
|
|
884
|
+
res.end();
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
try {
|
|
888
|
+
const fileHandle = await fs4.open(fileAbsolutePath, "r");
|
|
889
|
+
const fileData = await fs4.readFile(fileHandle);
|
|
890
|
+
res.setHeader("Content-type", lookup(ext) || "text/plain");
|
|
891
|
+
res.end(fileData);
|
|
892
|
+
fileHandle.close();
|
|
893
|
+
} catch (exception) {
|
|
894
|
+
if (!existsSync2(fileAbsolutePath)) {
|
|
895
|
+
res.statusCode = 404;
|
|
896
|
+
res.end();
|
|
897
|
+
} else {
|
|
898
|
+
const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
|
|
899
|
+
console.error(
|
|
900
|
+
`Could not read file at %s to be served, here's the exception:`,
|
|
901
|
+
sanitizedFilePath,
|
|
902
|
+
exception
|
|
903
|
+
);
|
|
904
|
+
res.statusCode = 500;
|
|
905
|
+
res.end(
|
|
906
|
+
"Could not read file to be served! Check your terminal for more information."
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
// src/utils/preview/start-dev-server.ts
|
|
913
|
+
var devServer;
|
|
914
|
+
var safeAsyncServerListen = (server, port) => {
|
|
915
|
+
return new Promise((resolve) => {
|
|
916
|
+
server.listen(port, () => {
|
|
917
|
+
resolve({ portAlreadyInUse: false });
|
|
918
|
+
});
|
|
919
|
+
server.on("error", (e) => {
|
|
920
|
+
if (e.code === "EADDRINUSE") {
|
|
921
|
+
resolve({ portAlreadyInUse: true });
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
});
|
|
925
|
+
};
|
|
926
|
+
var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
|
|
927
|
+
const [majorNodeVersion] = process.versions.node.split(".");
|
|
928
|
+
if (majorNodeVersion && Number.parseInt(majorNodeVersion) < 18) {
|
|
929
|
+
console.error(
|
|
930
|
+
` ${logSymbols3.error} Node ${majorNodeVersion} is not supported. Please upgrade to Node 18 or higher.`
|
|
931
|
+
);
|
|
932
|
+
process.exit(1);
|
|
933
|
+
}
|
|
934
|
+
const previewServerLocation = await getPreviewServerLocation();
|
|
935
|
+
const previewServer = createJiti2(previewServerLocation);
|
|
936
|
+
const { default: next } = await previewServer.import("next");
|
|
937
|
+
devServer = http.createServer((req, res) => {
|
|
938
|
+
if (!req.url) {
|
|
939
|
+
res.end(404);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
const parsedUrl = url2.parse(req.url, true);
|
|
943
|
+
res.setHeader(
|
|
944
|
+
"Cache-Control",
|
|
945
|
+
"no-cache, max-age=0, must-revalidate, no-store"
|
|
946
|
+
);
|
|
947
|
+
res.setHeader("Pragma", "no-cache");
|
|
948
|
+
res.setHeader("Expires", "-1");
|
|
949
|
+
try {
|
|
950
|
+
if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) {
|
|
951
|
+
void serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
|
|
952
|
+
} else if (!isNextReady) {
|
|
953
|
+
void nextReadyPromise.then(
|
|
954
|
+
() => nextHandleRequest?.(req, res, parsedUrl)
|
|
955
|
+
);
|
|
956
|
+
} else {
|
|
957
|
+
void nextHandleRequest?.(req, res, parsedUrl);
|
|
958
|
+
}
|
|
959
|
+
} catch (e) {
|
|
960
|
+
console.error("caught error", e);
|
|
961
|
+
res.writeHead(500);
|
|
962
|
+
res.end();
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
const { portAlreadyInUse } = await safeAsyncServerListen(devServer, port);
|
|
966
|
+
if (!portAlreadyInUse) {
|
|
967
|
+
console.log(chalk.greenBright(` React Email ${package_default.version}`));
|
|
968
|
+
console.log(` Running preview at: http://localhost:${port}
|
|
969
|
+
`);
|
|
970
|
+
} else {
|
|
971
|
+
const nextPortToTry = port + 1;
|
|
972
|
+
console.warn(
|
|
973
|
+
` ${logSymbols3.warning} Port ${port} is already in use, trying ${nextPortToTry}`
|
|
974
|
+
);
|
|
975
|
+
return startDevServer(
|
|
976
|
+
emailsDirRelativePath,
|
|
977
|
+
staticBaseDirRelativePath,
|
|
978
|
+
nextPortToTry
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
devServer.on("close", async () => {
|
|
982
|
+
await app.close();
|
|
983
|
+
});
|
|
984
|
+
devServer.on("error", (e) => {
|
|
985
|
+
spinner.stopAndPersist({
|
|
986
|
+
symbol: logSymbols3.error,
|
|
987
|
+
text: `Preview Server had an error: ${e}`
|
|
988
|
+
});
|
|
989
|
+
process.exit(1);
|
|
990
|
+
});
|
|
991
|
+
const spinner = ora2({
|
|
992
|
+
text: "Getting react-email preview server ready...\n",
|
|
993
|
+
prefixText: " "
|
|
994
|
+
}).start();
|
|
995
|
+
registerSpinnerAutostopping(spinner);
|
|
996
|
+
const timeBeforeNextReady = performance.now();
|
|
997
|
+
process.env = {
|
|
998
|
+
NODE_ENV: "development",
|
|
999
|
+
...process.env,
|
|
1000
|
+
...getEnvVariablesForPreviewApp(
|
|
1001
|
+
// If we don't do normalization here, stuff like https://github.com/resend/react-email/issues/1354 happens.
|
|
1002
|
+
path9.normalize(emailsDirRelativePath),
|
|
1003
|
+
process.cwd()
|
|
1004
|
+
)
|
|
1005
|
+
};
|
|
1006
|
+
const app = next({
|
|
1007
|
+
// passing in env here does not get the environment variables there
|
|
1008
|
+
dev: false,
|
|
1009
|
+
conf: {
|
|
1010
|
+
images: {
|
|
1011
|
+
// This is to avoid the warning with sharp
|
|
1012
|
+
unoptimized: true
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
hostname: "localhost",
|
|
1016
|
+
port,
|
|
1017
|
+
dir: previewServerLocation
|
|
1018
|
+
});
|
|
1019
|
+
let isNextReady = false;
|
|
1020
|
+
const nextReadyPromise = app.prepare();
|
|
1021
|
+
try {
|
|
1022
|
+
await nextReadyPromise;
|
|
1023
|
+
} catch (exception) {
|
|
1024
|
+
spinner.stopAndPersist({
|
|
1025
|
+
symbol: logSymbols3.error,
|
|
1026
|
+
text: ` Preview Server had an error: ${exception}`
|
|
1027
|
+
});
|
|
1028
|
+
process.exit(1);
|
|
1029
|
+
}
|
|
1030
|
+
isNextReady = true;
|
|
1031
|
+
const nextHandleRequest = app.getRequestHandler();
|
|
1032
|
+
const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
|
|
1033
|
+
spinner.stopAndPersist({
|
|
1034
|
+
text: `Ready in ${secondsToNextReady}s
|
|
1035
|
+
`,
|
|
1036
|
+
symbol: logSymbols3.success
|
|
1037
|
+
});
|
|
1038
|
+
return devServer;
|
|
1039
|
+
};
|
|
1040
|
+
var makeExitHandler = (options) => (codeSignalOrError) => {
|
|
1041
|
+
if (typeof devServer !== "undefined") {
|
|
1042
|
+
console.log("\nshutting down dev server");
|
|
1043
|
+
devServer.close();
|
|
1044
|
+
devServer = void 0;
|
|
1045
|
+
}
|
|
1046
|
+
if (codeSignalOrError instanceof Error) {
|
|
1047
|
+
console.error(codeSignalOrError);
|
|
1048
|
+
}
|
|
1049
|
+
if (options?.shouldKillProcess) {
|
|
1050
|
+
process.exit(options.killWithErrorCode ? 1 : 0);
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
process.on("exit", makeExitHandler());
|
|
1054
|
+
process.on(
|
|
1055
|
+
"SIGINT",
|
|
1056
|
+
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
|
|
1057
|
+
);
|
|
1058
|
+
process.on(
|
|
1059
|
+
"SIGUSR1",
|
|
1060
|
+
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
|
|
1061
|
+
);
|
|
1062
|
+
process.on(
|
|
1063
|
+
"SIGUSR2",
|
|
1064
|
+
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
|
|
1065
|
+
);
|
|
1066
|
+
process.on(
|
|
1067
|
+
"uncaughtException",
|
|
1068
|
+
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1059
1071
|
// src/utils/tree.ts
|
|
1060
1072
|
import { promises as fs5 } from "node:fs";
|
|
1061
1073
|
import os from "node:os";
|
|
@@ -1070,8 +1082,8 @@ var SYMBOLS = {
|
|
|
1070
1082
|
var getTreeLines = async (dirPath, depth, currentDepth = 0) => {
|
|
1071
1083
|
const base = process.cwd();
|
|
1072
1084
|
const dirFullpath = path10.resolve(base, dirPath);
|
|
1073
|
-
const
|
|
1074
|
-
let lines = [
|
|
1085
|
+
const dirname = path10.basename(dirFullpath);
|
|
1086
|
+
let lines = [dirname];
|
|
1075
1087
|
const dirStat = await fs5.stat(dirFullpath);
|
|
1076
1088
|
if (dirStat.isDirectory() && currentDepth < depth) {
|
|
1077
1089
|
const childDirents = await fs5.readdir(dirFullpath, { withFileTypes: true });
|
|
@@ -1200,15 +1212,15 @@ var renderingUtilitiesExporter = (emailTemplates) => ({
|
|
|
1200
1212
|
var getEmailTemplatesFromDirectory = (emailDirectory) => {
|
|
1201
1213
|
const templatePaths = [];
|
|
1202
1214
|
emailDirectory.emailFilenames.forEach(
|
|
1203
|
-
(
|
|
1215
|
+
(filename2) => templatePaths.push(path12.join(emailDirectory.absolutePath, filename2))
|
|
1204
1216
|
);
|
|
1205
1217
|
emailDirectory.subDirectories.forEach((directory) => {
|
|
1206
1218
|
templatePaths.push(...getEmailTemplatesFromDirectory(directory));
|
|
1207
1219
|
});
|
|
1208
1220
|
return templatePaths;
|
|
1209
1221
|
};
|
|
1210
|
-
var
|
|
1211
|
-
var require2 = createRequire(
|
|
1222
|
+
var filename = url3.fileURLToPath(import.meta.url);
|
|
1223
|
+
var require2 = createRequire(filename);
|
|
1212
1224
|
var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirectoryPath, options) => {
|
|
1213
1225
|
if (fs8.existsSync(pathToWhereEmailMarkupShouldBeDumped)) {
|
|
1214
1226
|
fs8.rmSync(pathToWhereEmailMarkupShouldBeDumped, { recursive: true });
|