react-email 4.0.7 → 4.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/cli/index.mjs +214 -186
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/app-build-manifest.json +14 -14
- package/dist/preview/.next/app-path-routes-manifest.json +1 -1
- package/dist/preview/.next/build-manifest.json +2 -2
- package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/preview/.next/next-server.js.nft.json +1 -1
- package/dist/preview/.next/prerender-manifest.json +3 -3
- package/dist/preview/.next/server/app/_not-found/page.js +1 -1
- package/dist/preview/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/page.js +1 -1
- package/dist/preview/.next/server/app/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page.js +137 -75
- package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app-paths-manifest.json +1 -1
- package/dist/preview/.next/server/chunks/267.js +14 -0
- package/dist/preview/.next/server/chunks/346.js +1 -0
- package/dist/preview/.next/server/chunks/{886.js → 775.js} +3 -3
- package/dist/preview/.next/server/pages/500.html +1 -1
- package/dist/preview/.next/server/server-reference-manifest.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.json +1 -1
- package/dist/preview/.next/static/chunks/33-ff3f70a80570ecda.js +1 -0
- package/dist/preview/.next/static/chunks/416-9c899340cfaa07d4.js +1 -0
- package/dist/preview/.next/static/chunks/516-2716d86d2f8b9000.js +1 -0
- package/dist/preview/.next/static/chunks/{587-352f8079202a48d0.js → 587-0644242ce9489212.js} +1 -1
- package/dist/preview/.next/static/chunks/app/layout-2726a60e293495d3.js +1 -0
- package/dist/preview/.next/static/chunks/app/{page-0ee3a37f3a3f6f17.js → page-1d98e2313c60dd77.js} +1 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-c77ff9f2bb1709b3.js +1 -0
- package/dist/preview/.next/static/chunks/f33a14d2-a04f3be0523bd1fa.js +6 -0
- package/dist/preview/.next/static/css/6f42d128f111d7fa.css +3 -0
- package/dist/preview/.next/trace +27 -27
- package/package.json +44 -46
- package/src/actions/email-validation/check-compatibility.ts +1 -1
- package/src/actions/email-validation/check-images.spec.tsx +1 -1
- package/src/actions/email-validation/check-links.spec.tsx +1 -1
- package/src/actions/email-validation/quick-fetch.ts +1 -1
- package/src/actions/render-email-by-path.tsx +6 -6
- package/src/app/preview/[...slug]/preview.tsx +1 -1
- package/src/commands/testing/out/magic-links/aws-verify-email.html +164 -0
- package/src/commands/testing/out/magic-links/linear-login-code.html +89 -0
- package/src/commands/testing/out/magic-links/notion-magic-link.html +75 -0
- package/src/commands/testing/out/magic-links/plaid-verify-identity.html +78 -0
- package/src/commands/testing/out/magic-links/raycast-magic-link.html +90 -0
- package/src/commands/testing/out/magic-links/slack-confirm.html +239 -0
- package/src/commands/testing/out/newsletters/codepen-challengers.html +547 -0
- package/src/commands/testing/out/newsletters/google-play-policy-update.html +338 -0
- package/src/commands/testing/out/newsletters/stack-overflow-tips.html +230 -0
- package/src/commands/testing/out/notifications/github-access-token.html +103 -0
- package/src/commands/testing/out/notifications/papermark-year-in-review.html +316 -0
- package/src/commands/testing/out/notifications/vercel-invite-user.html +170 -0
- package/src/commands/testing/out/notifications/yelp-recent-login.html +194 -0
- package/src/commands/testing/out/receipts/apple-receipt.html +676 -0
- package/src/commands/testing/out/receipts/nike-receipt.html +723 -0
- package/src/commands/testing/out/reset-password/dropbox-reset-password.html +97 -0
- package/src/commands/testing/out/reset-password/twitch-reset-password.html +219 -0
- package/src/commands/testing/out/reviews/airbnb-review.html +205 -0
- package/src/commands/testing/out/reviews/amazon-review.html +355 -0
- package/src/commands/testing/out/static/airbnb-logo.png +0 -0
- package/src/commands/testing/out/static/airbnb-review-user.jpg +0 -0
- package/src/commands/testing/out/static/amazon-book.jpg +0 -0
- package/src/commands/testing/out/static/amazon-facebook.jpg +0 -0
- package/src/commands/testing/out/static/amazon-instagram.jpg +0 -0
- package/src/commands/testing/out/static/amazon-logo.png +0 -0
- package/src/commands/testing/out/static/amazon-prime-logo.png +0 -0
- package/src/commands/testing/out/static/amazon-rating.gif +0 -0
- package/src/commands/testing/out/static/amazon-twitter.jpg +0 -0
- package/src/commands/testing/out/static/apple-card-icon.png +0 -0
- package/src/commands/testing/out/static/apple-hbo-max-icon.jpeg +0 -0
- package/src/commands/testing/out/static/apple-logo.png +0 -0
- package/src/commands/testing/out/static/apple-wallet.png +0 -0
- package/src/commands/testing/out/static/aws-logo.png +0 -0
- package/src/commands/testing/out/static/codepen-challengers.png +0 -0
- package/src/commands/testing/out/static/codepen-cube.png +0 -0
- package/src/commands/testing/out/static/codepen-pro.png +0 -0
- package/src/commands/testing/out/static/dropbox-logo.png +0 -0
- package/src/commands/testing/out/static/github.png +0 -0
- package/src/commands/testing/out/static/google-play-academy.png +0 -0
- package/src/commands/testing/out/static/google-play-chat.png +0 -0
- package/src/commands/testing/out/static/google-play-footer.png +0 -0
- package/src/commands/testing/out/static/google-play-header.png +0 -0
- package/src/commands/testing/out/static/google-play-icon.png +0 -0
- package/src/commands/testing/out/static/google-play-logo.png +0 -0
- package/src/commands/testing/out/static/google-play-pl.png +0 -0
- package/src/commands/testing/out/static/google-play.png +0 -0
- package/src/commands/testing/out/static/koala-logo.png +0 -0
- package/src/commands/testing/out/static/linear-logo.png +0 -0
- package/src/commands/testing/out/static/netlify-logo.png +0 -0
- package/src/commands/testing/out/static/nike-logo.png +0 -0
- package/src/commands/testing/out/static/nike-phone.png +0 -0
- package/src/commands/testing/out/static/nike-product.png +0 -0
- package/src/commands/testing/out/static/nike-recomendation-1.png +0 -0
- package/src/commands/testing/out/static/nike-recomendation-2.png +0 -0
- package/src/commands/testing/out/static/nike-recomendation-3.png +0 -0
- package/src/commands/testing/out/static/nike-recomendation-4.png +0 -0
- package/src/commands/testing/out/static/notion-logo.png +0 -0
- package/src/commands/testing/out/static/plaid-logo.png +0 -0
- package/src/commands/testing/out/static/raycast-bg.png +0 -0
- package/src/commands/testing/out/static/raycast-logo.png +0 -0
- package/src/commands/testing/out/static/slack-facebook.png +0 -0
- package/src/commands/testing/out/static/slack-linkedin.png +0 -0
- package/src/commands/testing/out/static/slack-logo.png +0 -0
- package/src/commands/testing/out/static/slack-twitter.png +0 -0
- package/src/commands/testing/out/static/stack-overflow-header.png +0 -0
- package/src/commands/testing/out/static/stack-overflow-logo-sm.png +0 -0
- package/src/commands/testing/out/static/stack-overflow-logo.png +0 -0
- package/src/commands/testing/out/static/stripe-logo.png +0 -0
- package/src/commands/testing/out/static/twitch-icon-facebook.png +0 -0
- package/src/commands/testing/out/static/twitch-icon-twitter.png +0 -0
- package/src/commands/testing/out/static/twitch-logo.png +0 -0
- package/src/commands/testing/out/static/vercel-arrow.png +0 -0
- package/src/commands/testing/out/static/vercel-logo.png +0 -0
- package/src/commands/testing/out/static/vercel-team.png +0 -0
- package/src/commands/testing/out/static/vercel-user.png +0 -0
- package/src/commands/testing/out/static/yelp-footer.png +0 -0
- package/src/commands/testing/out/static/yelp-header.png +0 -0
- package/src/commands/testing/out/static/yelp-logo.png +0 -0
- package/src/commands/testing/out/welcome/koala-welcome.html +89 -0
- package/src/commands/testing/out/welcome/netlify-welcome.html +198 -0
- package/src/commands/testing/out/welcome/stripe-welcome.html +152 -0
- package/src/components/toolbar.tsx +1 -0
- package/src/contexts/emails.tsx +1 -3
- package/src/contexts/fragment-identifier.tsx +3 -1
- package/src/contexts/preview.tsx +1 -3
- package/src/hooks/use-email-rendering-result.ts +18 -5
- package/src/hooks/use-hot-reload.ts +1 -1
- package/src/utils/__snapshots__/get-email-component.spec.ts.snap +1 -1
- package/src/utils/caniemail/ast/get-object-variables.ts +1 -1
- package/src/utils/caniemail/tailwind/generate-tailwind-rules.ts +1 -1
- package/src/utils/caniemail/tailwind/get-tailwind-config.ts +1 -1
- package/src/utils/caniemail/tailwind/get-tailwind-metadata.ts +1 -1
- package/src/utils/contains-email-template.spec.ts +107 -0
- package/src/utils/contains-email-template.ts +33 -0
- package/src/utils/get-email-component.ts +16 -1
- package/src/utils/get-emails-directory-metadata.ts +24 -13
- package/src/utils/index.ts +2 -2
- package/src/utils/run-bundled-code.ts +1 -1
- package/tailwind.config.ts +2 -1
- package/tsconfig.json +1 -1
- package/dist/cli/index.d.mts +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -1317
- package/dist/preview/.next/server/chunks/380.js +0 -1
- package/dist/preview/.next/server/chunks/840.js +0 -14
- package/dist/preview/.next/static/chunks/246-e7336e2929971f63.js +0 -1
- package/dist/preview/.next/static/chunks/539-6e9405ecdc007bb7.js +0 -1
- package/dist/preview/.next/static/chunks/853-a01d49f63a859f3d.js +0 -1
- package/dist/preview/.next/static/chunks/afa401a5-55858bf5265319eb.js +0 -6
- package/dist/preview/.next/static/chunks/app/layout-fa93a7ef0cc5ebdb.js +0 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-95449af2d870e732.js +0 -1
- package/dist/preview/.next/static/css/67e57230289273a9.css +0 -3
- /package/dist/preview/.next/static/{Oy7kpIZ6Nbnd7hpoEKBWw → 3apYH6rky7aNn7g4RIJp5}/_buildManifest.js +0 -0
- /package/dist/preview/.next/static/{Oy7kpIZ6Nbnd7hpoEKBWw → 3apYH6rky7aNn7g4RIJp5}/_ssgManifest.js +0 -0
package/dist/cli/index.js
DELETED
|
@@ -1,1317 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
for (let key of __getOwnPropNames(from))
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
-
}
|
|
14
|
-
return to;
|
|
15
|
-
};
|
|
16
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
-
mod
|
|
23
|
-
));
|
|
24
|
-
|
|
25
|
-
// src/cli/index.ts
|
|
26
|
-
var import_commander = require("commander");
|
|
27
|
-
|
|
28
|
-
// package.json
|
|
29
|
-
var package_default = {
|
|
30
|
-
name: "react-email",
|
|
31
|
-
version: "4.0.7",
|
|
32
|
-
description: "A live preview of your emails right in your browser.",
|
|
33
|
-
bin: {
|
|
34
|
-
email: "./dist/cli/index.js"
|
|
35
|
-
},
|
|
36
|
-
scripts: {
|
|
37
|
-
build: "tsup-node && node ./scripts/build-preview-server.mjs && pnpm install --frozen-lockfile",
|
|
38
|
-
"caniemail:fetch": "node ./scripts/fill-caniemail-data.mjs",
|
|
39
|
-
clean: "rm -rf dist",
|
|
40
|
-
dev: "tsup-node --watch",
|
|
41
|
-
"dev:preview": "cd ../../apps/demo && tsx ../../packages/react-email/src/cli/index.ts dev",
|
|
42
|
-
test: "vitest run",
|
|
43
|
-
"test:watch": "vitest"
|
|
44
|
-
},
|
|
45
|
-
license: "MIT",
|
|
46
|
-
repository: {
|
|
47
|
-
type: "git",
|
|
48
|
-
url: "https://github.com/resend/react-email.git",
|
|
49
|
-
directory: "packages/react-email"
|
|
50
|
-
},
|
|
51
|
-
keywords: ["react", "email"],
|
|
52
|
-
engines: {
|
|
53
|
-
node: ">=18.0.0"
|
|
54
|
-
},
|
|
55
|
-
dependencies: {
|
|
56
|
-
"@babel/parser": "7.24.5",
|
|
57
|
-
"@babel/traverse": "7.25.6",
|
|
58
|
-
chalk: "4.1.2",
|
|
59
|
-
chokidar: "4.0.3",
|
|
60
|
-
commander: "11.1.0",
|
|
61
|
-
debounce: "2.0.0",
|
|
62
|
-
esbuild: "0.25.0",
|
|
63
|
-
glob: "10.3.4",
|
|
64
|
-
"log-symbols": "4.1.0",
|
|
65
|
-
"mime-types": "2.1.35",
|
|
66
|
-
next: "15.2.4",
|
|
67
|
-
"normalize-path": "3.0.0",
|
|
68
|
-
ora: "5.4.1",
|
|
69
|
-
"socket.io": "4.8.1"
|
|
70
|
-
},
|
|
71
|
-
devDependencies: {
|
|
72
|
-
"@babel/core": "7.26.10",
|
|
73
|
-
"@lottiefiles/dotlottie-react": "0.12.3",
|
|
74
|
-
"@radix-ui/colors": "1.0.1",
|
|
75
|
-
"@radix-ui/react-collapsible": "1.1.0",
|
|
76
|
-
"@radix-ui/react-dropdown-menu": "2.1.4",
|
|
77
|
-
"@radix-ui/react-popover": "1.1.1",
|
|
78
|
-
"@radix-ui/react-slot": "1.1.0",
|
|
79
|
-
"@radix-ui/react-tabs": "1.1.1",
|
|
80
|
-
"@radix-ui/react-toggle-group": "1.1.0",
|
|
81
|
-
"@radix-ui/react-tooltip": "1.1.2",
|
|
82
|
-
"@react-email/components": "workspace:*",
|
|
83
|
-
"@swc/core": "1.4.15",
|
|
84
|
-
"@types/babel__core": "7.20.5",
|
|
85
|
-
"@types/babel__traverse": "*",
|
|
86
|
-
"@types/fs-extra": "11.0.1",
|
|
87
|
-
"@types/mime-types": "2.1.4",
|
|
88
|
-
"@types/node": "22.10.2",
|
|
89
|
-
"@types/normalize-path": "3.0.2",
|
|
90
|
-
"@types/react": "19.0.10",
|
|
91
|
-
"@types/react-dom": "19.0.4",
|
|
92
|
-
"@types/webpack": "5.28.5",
|
|
93
|
-
"@vercel/style-guide": "5.1.0",
|
|
94
|
-
autoprefixer: "10.4.20",
|
|
95
|
-
clsx: "2.1.1",
|
|
96
|
-
"framer-motion": "12.0.0-alpha.2",
|
|
97
|
-
jiti: "2.4.2",
|
|
98
|
-
json5: "2.2.3",
|
|
99
|
-
"module-punycode": "npm:punycode@2.3.1",
|
|
100
|
-
"node-html-parser": "6.1.13",
|
|
101
|
-
postcss: "8.4.40",
|
|
102
|
-
"prettier-plugin-tailwindcss": "0.6.6",
|
|
103
|
-
"pretty-bytes": "6.1.1",
|
|
104
|
-
"prism-react-renderer": "2.1.0",
|
|
105
|
-
react: "19.0.0",
|
|
106
|
-
"react-dom": "19.0.0",
|
|
107
|
-
sharp: "0.33.3",
|
|
108
|
-
"socket.io-client": "4.8.0",
|
|
109
|
-
sonner: "1.7.1",
|
|
110
|
-
"source-map-js": "1.0.2",
|
|
111
|
-
spamc: "0.0.5",
|
|
112
|
-
"stacktrace-parser": "0.1.10",
|
|
113
|
-
"tailwind-merge": "2.2.0",
|
|
114
|
-
tailwindcss: "3.4.0",
|
|
115
|
-
tsup: "7.2.0",
|
|
116
|
-
tsx: "4.9.0",
|
|
117
|
-
typescript: "5.8.2",
|
|
118
|
-
"use-debounce": "10.0.4",
|
|
119
|
-
zod: "3.24.2"
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
// src/cli/commands/build.ts
|
|
124
|
-
var import_node_child_process = require("child_process");
|
|
125
|
-
var import_node_fs5 = __toESM(require("fs"));
|
|
126
|
-
var import_node_path8 = __toESM(require("path"));
|
|
127
|
-
var import_log_symbols3 = __toESM(require("log-symbols"));
|
|
128
|
-
var import_ora2 = __toESM(require("ora"));
|
|
129
|
-
|
|
130
|
-
// src/utils/get-emails-directory-metadata.ts
|
|
131
|
-
var import_node_fs = __toESM(require("fs"));
|
|
132
|
-
var import_node_path = __toESM(require("path"));
|
|
133
|
-
var isFileAnEmail = (fullPath) => {
|
|
134
|
-
const stat = import_node_fs.default.statSync(fullPath);
|
|
135
|
-
if (stat.isDirectory())
|
|
136
|
-
return false;
|
|
137
|
-
const { ext } = import_node_path.default.parse(fullPath);
|
|
138
|
-
if (![".js", ".tsx", ".jsx"].includes(ext))
|
|
139
|
-
return false;
|
|
140
|
-
if (!import_node_fs.default.existsSync(fullPath)) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
const fileContents = import_node_fs.default.readFileSync(fullPath, "utf8");
|
|
144
|
-
const hasES6DefaultExport = /\bexport\s+default\b/gm.test(fileContents);
|
|
145
|
-
const hasCommonJSExport = /\bmodule\.exports\s*=/gm.test(fileContents);
|
|
146
|
-
const hasNamedExport = /\bexport\s+\{[^}]*\bdefault\b[^}]*\}/gm.test(
|
|
147
|
-
fileContents
|
|
148
|
-
);
|
|
149
|
-
return hasES6DefaultExport || hasCommonJSExport || hasNamedExport;
|
|
150
|
-
};
|
|
151
|
-
var mergeDirectoriesWithSubDirectories = (emailsDirectoryMetadata) => {
|
|
152
|
-
let currentResultingMergedDirectory = emailsDirectoryMetadata;
|
|
153
|
-
while (currentResultingMergedDirectory.emailFilenames.length === 0 && currentResultingMergedDirectory.subDirectories.length === 1) {
|
|
154
|
-
const onlySubDirectory = currentResultingMergedDirectory.subDirectories[0];
|
|
155
|
-
currentResultingMergedDirectory = {
|
|
156
|
-
...onlySubDirectory,
|
|
157
|
-
directoryName: import_node_path.default.join(
|
|
158
|
-
currentResultingMergedDirectory.directoryName,
|
|
159
|
-
onlySubDirectory.directoryName
|
|
160
|
-
)
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
return currentResultingMergedDirectory;
|
|
164
|
-
};
|
|
165
|
-
var getEmailsDirectoryMetadata = async (absolutePathToEmailsDirectory, keepFileExtensions = false, isSubDirectory = false, baseDirectoryPath = absolutePathToEmailsDirectory) => {
|
|
166
|
-
if (!import_node_fs.default.existsSync(absolutePathToEmailsDirectory))
|
|
167
|
-
return;
|
|
168
|
-
const dirents = await import_node_fs.default.promises.readdir(absolutePathToEmailsDirectory, {
|
|
169
|
-
withFileTypes: true
|
|
170
|
-
});
|
|
171
|
-
const emailFilenames = dirents.filter(
|
|
172
|
-
(dirent) => isFileAnEmail(import_node_path.default.join(absolutePathToEmailsDirectory, dirent.name))
|
|
173
|
-
).map(
|
|
174
|
-
(dirent) => keepFileExtensions ? dirent.name : dirent.name.replace(import_node_path.default.extname(dirent.name), "")
|
|
175
|
-
);
|
|
176
|
-
const subDirectories = await Promise.all(
|
|
177
|
-
dirents.filter(
|
|
178
|
-
(dirent) => dirent.isDirectory() && !dirent.name.startsWith("_") && dirent.name !== "static"
|
|
179
|
-
).map((dirent) => {
|
|
180
|
-
const direntAbsolutePath = import_node_path.default.join(
|
|
181
|
-
absolutePathToEmailsDirectory,
|
|
182
|
-
dirent.name
|
|
183
|
-
);
|
|
184
|
-
return getEmailsDirectoryMetadata(
|
|
185
|
-
direntAbsolutePath,
|
|
186
|
-
keepFileExtensions,
|
|
187
|
-
true,
|
|
188
|
-
baseDirectoryPath
|
|
189
|
-
);
|
|
190
|
-
})
|
|
191
|
-
);
|
|
192
|
-
const emailsMetadata = {
|
|
193
|
-
absolutePath: absolutePathToEmailsDirectory,
|
|
194
|
-
relativePath: import_node_path.default.relative(
|
|
195
|
-
baseDirectoryPath,
|
|
196
|
-
absolutePathToEmailsDirectory
|
|
197
|
-
),
|
|
198
|
-
directoryName: absolutePathToEmailsDirectory.split(import_node_path.default.sep).pop(),
|
|
199
|
-
emailFilenames,
|
|
200
|
-
subDirectories
|
|
201
|
-
};
|
|
202
|
-
return isSubDirectory ? mergeDirectoriesWithSubDirectories(emailsMetadata) : emailsMetadata;
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// src/utils/register-spinner-autostopping.ts
|
|
206
|
-
var import_log_symbols = __toESM(require("log-symbols"));
|
|
207
|
-
var spinners = /* @__PURE__ */ new Set();
|
|
208
|
-
process.on("SIGINT", () => {
|
|
209
|
-
spinners.forEach((spinner) => {
|
|
210
|
-
if (spinner.isSpinning) {
|
|
211
|
-
spinner.stop();
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
process.on("exit", (code) => {
|
|
216
|
-
if (code !== 0) {
|
|
217
|
-
spinners.forEach((spinner) => {
|
|
218
|
-
if (spinner.isSpinning) {
|
|
219
|
-
spinner.stopAndPersist({
|
|
220
|
-
symbol: import_log_symbols.default.error
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
var registerSpinnerAutostopping = (spinner) => {
|
|
227
|
-
spinners.add(spinner);
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
// src/cli/utils/tree.ts
|
|
231
|
-
var import_node_fs2 = require("fs");
|
|
232
|
-
var import_node_os = __toESM(require("os"));
|
|
233
|
-
var import_node_path2 = __toESM(require("path"));
|
|
234
|
-
var SYMBOLS = {
|
|
235
|
-
BRANCH: "\u251C\u2500\u2500 ",
|
|
236
|
-
EMPTY: "",
|
|
237
|
-
INDENT: " ",
|
|
238
|
-
LAST_BRANCH: "\u2514\u2500\u2500 ",
|
|
239
|
-
VERTICAL: "\u2502 "
|
|
240
|
-
};
|
|
241
|
-
var getTreeLines = async (dirPath, depth, currentDepth = 0) => {
|
|
242
|
-
const base = process.cwd();
|
|
243
|
-
const dirFullpath = import_node_path2.default.resolve(base, dirPath);
|
|
244
|
-
const dirname = import_node_path2.default.basename(dirFullpath);
|
|
245
|
-
let lines = [dirname];
|
|
246
|
-
const dirStat = await import_node_fs2.promises.stat(dirFullpath);
|
|
247
|
-
if (dirStat.isDirectory() && currentDepth < depth) {
|
|
248
|
-
const childDirents = await import_node_fs2.promises.readdir(dirFullpath, { withFileTypes: true });
|
|
249
|
-
childDirents.sort((a, b) => {
|
|
250
|
-
if (a.isDirectory() && b.isFile()) {
|
|
251
|
-
return -1;
|
|
252
|
-
}
|
|
253
|
-
if (a.isFile() && b.isDirectory()) {
|
|
254
|
-
return 1;
|
|
255
|
-
}
|
|
256
|
-
return b.name > a.name ? -1 : 1;
|
|
257
|
-
});
|
|
258
|
-
for (let i = 0; i < childDirents.length; i++) {
|
|
259
|
-
const dirent = childDirents[i];
|
|
260
|
-
const isLast = i === childDirents.length - 1;
|
|
261
|
-
const branchingSymbol = isLast ? SYMBOLS.LAST_BRANCH : SYMBOLS.BRANCH;
|
|
262
|
-
const verticalSymbol = isLast ? SYMBOLS.INDENT : SYMBOLS.VERTICAL;
|
|
263
|
-
if (dirent.isFile()) {
|
|
264
|
-
lines.push(`${branchingSymbol}${dirent.name}`);
|
|
265
|
-
} else {
|
|
266
|
-
const pathToDirectory = import_node_path2.default.join(dirFullpath, dirent.name);
|
|
267
|
-
const treeLinesForSubDirectory = await getTreeLines(
|
|
268
|
-
pathToDirectory,
|
|
269
|
-
depth,
|
|
270
|
-
currentDepth + 1
|
|
271
|
-
);
|
|
272
|
-
lines = lines.concat(
|
|
273
|
-
treeLinesForSubDirectory.map(
|
|
274
|
-
(line, index) => index === 0 ? `${branchingSymbol}${line}` : `${verticalSymbol}${line}`
|
|
275
|
-
)
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return lines;
|
|
281
|
-
};
|
|
282
|
-
var tree = async (dirPath, depth) => {
|
|
283
|
-
const lines = await getTreeLines(dirPath, depth);
|
|
284
|
-
return lines.join(import_node_os.default.EOL);
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
// src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts
|
|
288
|
-
var import_node_path7 = __toESM(require("path"));
|
|
289
|
-
var import_chokidar = require("chokidar");
|
|
290
|
-
var import_debounce = __toESM(require("debounce"));
|
|
291
|
-
var import_socket = require("socket.io");
|
|
292
|
-
|
|
293
|
-
// src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
|
|
294
|
-
var import_node_fs4 = require("fs");
|
|
295
|
-
var import_node_path6 = __toESM(require("path"));
|
|
296
|
-
|
|
297
|
-
// src/cli/utils/preview/start-dev-server.ts
|
|
298
|
-
var import_node_http = __toESM(require("http"));
|
|
299
|
-
var import_node_path5 = __toESM(require("path"));
|
|
300
|
-
var import_node_url = __toESM(require("url"));
|
|
301
|
-
var import_chalk = __toESM(require("chalk"));
|
|
302
|
-
var import_log_symbols2 = __toESM(require("log-symbols"));
|
|
303
|
-
var import_next = __toESM(require("next"));
|
|
304
|
-
var import_ora = __toESM(require("ora"));
|
|
305
|
-
|
|
306
|
-
// src/cli/utils/preview/get-env-variables-for-preview-app.ts
|
|
307
|
-
var import_node_path3 = __toESM(require("path"));
|
|
308
|
-
var getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, cwd) => {
|
|
309
|
-
return {
|
|
310
|
-
EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
|
|
311
|
-
EMAILS_DIR_ABSOLUTE_PATH: import_node_path3.default.resolve(cwd, relativePathToEmailsDirectory),
|
|
312
|
-
USER_PROJECT_LOCATION: cwd,
|
|
313
|
-
NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
|
|
314
|
-
};
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
// src/cli/utils/preview/serve-static-file.ts
|
|
318
|
-
var import_node_fs3 = require("fs");
|
|
319
|
-
var import_node_path4 = __toESM(require("path"));
|
|
320
|
-
var import_mime_types = require("mime-types");
|
|
321
|
-
var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
|
|
322
|
-
const staticBaseDir = import_node_path4.default.join(process.cwd(), staticDirRelativePath);
|
|
323
|
-
const pathname = parsedUrl.pathname;
|
|
324
|
-
const ext = import_node_path4.default.parse(pathname).ext;
|
|
325
|
-
const fileAbsolutePath = import_node_path4.default.join(staticBaseDir, pathname);
|
|
326
|
-
try {
|
|
327
|
-
const fileHandle = await import_node_fs3.promises.open(fileAbsolutePath, "r");
|
|
328
|
-
const fileData = await import_node_fs3.promises.readFile(fileHandle);
|
|
329
|
-
res.setHeader("Content-type", (0, import_mime_types.lookup)(ext) || "text/plain");
|
|
330
|
-
res.end(fileData);
|
|
331
|
-
fileHandle.close();
|
|
332
|
-
} catch (exception) {
|
|
333
|
-
if (!(0, import_node_fs3.existsSync)(fileAbsolutePath)) {
|
|
334
|
-
res.statusCode = 404;
|
|
335
|
-
res.end();
|
|
336
|
-
} else {
|
|
337
|
-
const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
|
|
338
|
-
console.error(
|
|
339
|
-
`Could not read file at ${sanitizedFilePath} to be served, here's the exception:`,
|
|
340
|
-
exception
|
|
341
|
-
);
|
|
342
|
-
res.statusCode = 500;
|
|
343
|
-
res.end(
|
|
344
|
-
"Could not read file to be served! Check your terminal for more information."
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
// src/cli/utils/preview/start-dev-server.ts
|
|
351
|
-
var devServer;
|
|
352
|
-
var safeAsyncServerListen = (server, port) => {
|
|
353
|
-
return new Promise((resolve) => {
|
|
354
|
-
server.listen(port, () => {
|
|
355
|
-
resolve({ portAlreadyInUse: false });
|
|
356
|
-
});
|
|
357
|
-
server.on("error", (e) => {
|
|
358
|
-
if (e.code === "EADDRINUSE") {
|
|
359
|
-
resolve({ portAlreadyInUse: true });
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
};
|
|
364
|
-
var isDev = !__filename.endsWith(import_node_path5.default.join("cli", "index.js"));
|
|
365
|
-
var cliPackageLocation = isDev ? import_node_path5.default.resolve(__dirname, "../../../..") : import_node_path5.default.resolve(__dirname, "../..");
|
|
366
|
-
var previewServerLocation = isDev ? import_node_path5.default.resolve(__dirname, "../../../..") : import_node_path5.default.resolve(__dirname, "../preview");
|
|
367
|
-
var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
|
|
368
|
-
devServer = import_node_http.default.createServer((req, res) => {
|
|
369
|
-
if (!req.url) {
|
|
370
|
-
res.end(404);
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
const parsedUrl = import_node_url.default.parse(req.url, true);
|
|
374
|
-
res.setHeader(
|
|
375
|
-
"Cache-Control",
|
|
376
|
-
"no-cache, max-age=0, must-revalidate, no-store"
|
|
377
|
-
);
|
|
378
|
-
res.setHeader("Pragma", "no-cache");
|
|
379
|
-
res.setHeader("Expires", "-1");
|
|
380
|
-
try {
|
|
381
|
-
if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) {
|
|
382
|
-
void serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
|
|
383
|
-
} else if (!isNextReady) {
|
|
384
|
-
void nextReadyPromise.then(
|
|
385
|
-
() => nextHandleRequest?.(req, res, parsedUrl)
|
|
386
|
-
);
|
|
387
|
-
} else {
|
|
388
|
-
void nextHandleRequest?.(req, res, parsedUrl);
|
|
389
|
-
}
|
|
390
|
-
} catch (e) {
|
|
391
|
-
console.error("caught error", e);
|
|
392
|
-
res.writeHead(500);
|
|
393
|
-
res.end();
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
const { portAlreadyInUse } = await safeAsyncServerListen(devServer, port);
|
|
397
|
-
if (!portAlreadyInUse) {
|
|
398
|
-
console.log(import_chalk.default.greenBright(` React Email ${package_default.version}`));
|
|
399
|
-
console.log(` Running preview at: http://localhost:${port}
|
|
400
|
-
`);
|
|
401
|
-
} else {
|
|
402
|
-
const nextPortToTry = port + 1;
|
|
403
|
-
console.warn(
|
|
404
|
-
` ${import_log_symbols2.default.warning} Port ${port} is already in use, trying ${nextPortToTry}`
|
|
405
|
-
);
|
|
406
|
-
return startDevServer(
|
|
407
|
-
emailsDirRelativePath,
|
|
408
|
-
staticBaseDirRelativePath,
|
|
409
|
-
nextPortToTry
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
devServer.on("close", async () => {
|
|
413
|
-
await app.close();
|
|
414
|
-
});
|
|
415
|
-
devServer.on("error", (e) => {
|
|
416
|
-
console.error(
|
|
417
|
-
` ${import_log_symbols2.default.error} preview server error: `,
|
|
418
|
-
JSON.stringify(e)
|
|
419
|
-
);
|
|
420
|
-
process.exit(1);
|
|
421
|
-
});
|
|
422
|
-
const spinner = (0, import_ora.default)({
|
|
423
|
-
text: "Getting react-email preview server ready...\n",
|
|
424
|
-
prefixText: " "
|
|
425
|
-
}).start();
|
|
426
|
-
registerSpinnerAutostopping(spinner);
|
|
427
|
-
const timeBeforeNextReady = performance.now();
|
|
428
|
-
process.env = {
|
|
429
|
-
NODE_ENV: "development",
|
|
430
|
-
...process.env,
|
|
431
|
-
...getEnvVariablesForPreviewApp(
|
|
432
|
-
// If we don't do normalization here, stuff like https://github.com/resend/react-email/issues/1354 happens.
|
|
433
|
-
import_node_path5.default.normalize(emailsDirRelativePath),
|
|
434
|
-
process.cwd()
|
|
435
|
-
)
|
|
436
|
-
};
|
|
437
|
-
const app = (0, import_next.default)({
|
|
438
|
-
// passing in env here does not get the environment variables there
|
|
439
|
-
dev: isDev,
|
|
440
|
-
conf: {
|
|
441
|
-
images: {
|
|
442
|
-
// This is to avoid the warning with sharp
|
|
443
|
-
unoptimized: true
|
|
444
|
-
}
|
|
445
|
-
},
|
|
446
|
-
hostname: "localhost",
|
|
447
|
-
port,
|
|
448
|
-
dir: previewServerLocation
|
|
449
|
-
});
|
|
450
|
-
let isNextReady = false;
|
|
451
|
-
const nextReadyPromise = app.prepare();
|
|
452
|
-
await nextReadyPromise;
|
|
453
|
-
isNextReady = true;
|
|
454
|
-
const nextHandleRequest = app.getRequestHandler();
|
|
455
|
-
const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
|
|
456
|
-
spinner.stopAndPersist({
|
|
457
|
-
text: `Ready in ${secondsToNextReady}s
|
|
458
|
-
`,
|
|
459
|
-
symbol: import_log_symbols2.default.success
|
|
460
|
-
});
|
|
461
|
-
return devServer;
|
|
462
|
-
};
|
|
463
|
-
var makeExitHandler = (options) => (_codeOrSignal) => {
|
|
464
|
-
if (typeof devServer !== "undefined") {
|
|
465
|
-
console.log("\nshutting down dev server");
|
|
466
|
-
devServer.close();
|
|
467
|
-
devServer = void 0;
|
|
468
|
-
}
|
|
469
|
-
if (options?.shouldKillProcess) {
|
|
470
|
-
process.exit(options.killWithErrorCode ? 1 : 0);
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
process.on("exit", makeExitHandler());
|
|
474
|
-
process.on(
|
|
475
|
-
"SIGINT",
|
|
476
|
-
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
|
|
477
|
-
);
|
|
478
|
-
process.on(
|
|
479
|
-
"SIGUSR1",
|
|
480
|
-
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
|
|
481
|
-
);
|
|
482
|
-
process.on(
|
|
483
|
-
"SIGUSR2",
|
|
484
|
-
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
|
|
485
|
-
);
|
|
486
|
-
process.on(
|
|
487
|
-
"uncaughtException",
|
|
488
|
-
makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
|
|
489
|
-
);
|
|
490
|
-
|
|
491
|
-
// src/cli/utils/preview/hot-reloading/get-imported-modules.ts
|
|
492
|
-
var import_parser = require("@babel/parser");
|
|
493
|
-
var import_traverse = __toESM(require("@babel/traverse"));
|
|
494
|
-
var getImportedModules = (contents) => {
|
|
495
|
-
const importedPaths = [];
|
|
496
|
-
const parsedContents = (0, import_parser.parse)(contents, {
|
|
497
|
-
sourceType: "unambiguous",
|
|
498
|
-
strictMode: false,
|
|
499
|
-
errorRecovery: true,
|
|
500
|
-
plugins: ["jsx", "typescript", "decorators"]
|
|
501
|
-
});
|
|
502
|
-
(0, import_traverse.default)(parsedContents, {
|
|
503
|
-
ImportDeclaration({ node }) {
|
|
504
|
-
importedPaths.push(node.source.value);
|
|
505
|
-
},
|
|
506
|
-
ExportAllDeclaration({ node }) {
|
|
507
|
-
importedPaths.push(node.source.value);
|
|
508
|
-
},
|
|
509
|
-
ExportNamedDeclaration({ node }) {
|
|
510
|
-
if (node.source) {
|
|
511
|
-
importedPaths.push(node.source.value);
|
|
512
|
-
}
|
|
513
|
-
},
|
|
514
|
-
CallExpression({ node }) {
|
|
515
|
-
if ("name" in node.callee && node.callee.name === "require") {
|
|
516
|
-
if (node.arguments.length === 1) {
|
|
517
|
-
const importPathNode = node.arguments[0];
|
|
518
|
-
if (importPathNode.type === "StringLiteral") {
|
|
519
|
-
importedPaths.push(importPathNode.value);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
});
|
|
525
|
-
return importedPaths;
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
// src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
|
|
529
|
-
var readAllFilesInsideDirectory = async (directory) => {
|
|
530
|
-
let allFilePaths = [];
|
|
531
|
-
const topLevelDirents = await import_node_fs4.promises.readdir(directory, { withFileTypes: true });
|
|
532
|
-
for await (const dirent of topLevelDirents) {
|
|
533
|
-
const pathToDirent = import_node_path6.default.join(directory, dirent.name);
|
|
534
|
-
if (dirent.isDirectory()) {
|
|
535
|
-
allFilePaths = allFilePaths.concat(
|
|
536
|
-
await readAllFilesInsideDirectory(pathToDirent)
|
|
537
|
-
);
|
|
538
|
-
} else {
|
|
539
|
-
allFilePaths.push(pathToDirent);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return allFilePaths;
|
|
543
|
-
};
|
|
544
|
-
var isJavascriptModule = (filePath) => {
|
|
545
|
-
const extensionName = import_node_path6.default.extname(filePath);
|
|
546
|
-
return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
|
|
547
|
-
};
|
|
548
|
-
var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
|
|
549
|
-
if ((0, import_node_fs4.existsSync)(`${pathWithoutExtension}.ts`)) {
|
|
550
|
-
return `${pathWithoutExtension}.ts`;
|
|
551
|
-
}
|
|
552
|
-
if ((0, import_node_fs4.existsSync)(`${pathWithoutExtension}.tsx`)) {
|
|
553
|
-
return `${pathWithoutExtension}.tsx`;
|
|
554
|
-
}
|
|
555
|
-
if ((0, import_node_fs4.existsSync)(`${pathWithoutExtension}.js`)) {
|
|
556
|
-
return `${pathWithoutExtension}.js`;
|
|
557
|
-
}
|
|
558
|
-
if ((0, import_node_fs4.existsSync)(`${pathWithoutExtension}.jsx`)) {
|
|
559
|
-
return `${pathWithoutExtension}.jsx`;
|
|
560
|
-
}
|
|
561
|
-
if ((0, import_node_fs4.existsSync)(`${pathWithoutExtension}.mjs`)) {
|
|
562
|
-
return `${pathWithoutExtension}.mjs`;
|
|
563
|
-
}
|
|
564
|
-
if ((0, import_node_fs4.existsSync)(`${pathWithoutExtension}.cjs`)) {
|
|
565
|
-
return `${pathWithoutExtension}.cjs`;
|
|
566
|
-
}
|
|
567
|
-
};
|
|
568
|
-
var createDependencyGraph = async (directory) => {
|
|
569
|
-
const filePaths = await readAllFilesInsideDirectory(directory);
|
|
570
|
-
const modulePaths = filePaths.filter(isJavascriptModule);
|
|
571
|
-
const graph = Object.fromEntries(
|
|
572
|
-
modulePaths.map((path12) => [
|
|
573
|
-
path12,
|
|
574
|
-
{
|
|
575
|
-
path: path12,
|
|
576
|
-
dependencyPaths: [],
|
|
577
|
-
dependentPaths: [],
|
|
578
|
-
moduleDependencies: []
|
|
579
|
-
}
|
|
580
|
-
])
|
|
581
|
-
);
|
|
582
|
-
const getDependencyPaths = async (filePath) => {
|
|
583
|
-
const contents = await import_node_fs4.promises.readFile(filePath, "utf8");
|
|
584
|
-
const importedPaths = getImportedModules(contents);
|
|
585
|
-
const importedPathsRelativeToDirectory = importedPaths.map(
|
|
586
|
-
(dependencyPath) => {
|
|
587
|
-
const isModulePath = !dependencyPath.startsWith(".");
|
|
588
|
-
if (isModulePath || import_node_path6.default.isAbsolute(dependencyPath)) {
|
|
589
|
-
return dependencyPath;
|
|
590
|
-
}
|
|
591
|
-
let pathToDependencyFromDirectory = import_node_path6.default.resolve(
|
|
592
|
-
/*
|
|
593
|
-
path.resolve resolves paths differently from what imports on javascript do.
|
|
594
|
-
|
|
595
|
-
So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependecy path of "./other-email"
|
|
596
|
-
would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
|
|
597
|
-
one the import is meant to go to
|
|
598
|
-
*/
|
|
599
|
-
import_node_path6.default.dirname(filePath),
|
|
600
|
-
dependencyPath
|
|
601
|
-
);
|
|
602
|
-
let isDirectory = false;
|
|
603
|
-
try {
|
|
604
|
-
isDirectory = (0, import_node_fs4.statSync)(pathToDependencyFromDirectory).isDirectory();
|
|
605
|
-
} catch (_) {
|
|
606
|
-
}
|
|
607
|
-
if (isDirectory) {
|
|
608
|
-
const pathToSubDirectory = pathToDependencyFromDirectory;
|
|
609
|
-
const pathWithExtension = checkFileExtensionsUntilItExists(
|
|
610
|
-
`${pathToSubDirectory}/index`
|
|
611
|
-
);
|
|
612
|
-
if (pathWithExtension) {
|
|
613
|
-
pathToDependencyFromDirectory = pathWithExtension;
|
|
614
|
-
} else if (isDev) {
|
|
615
|
-
console.warn(
|
|
616
|
-
`Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
|
|
617
|
-
);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
if (!isJavascriptModule(pathToDependencyFromDirectory)) {
|
|
621
|
-
const pathWithExtension = checkFileExtensionsUntilItExists(
|
|
622
|
-
pathToDependencyFromDirectory
|
|
623
|
-
);
|
|
624
|
-
if (pathWithExtension) {
|
|
625
|
-
pathToDependencyFromDirectory = pathWithExtension;
|
|
626
|
-
} else if (isDev) {
|
|
627
|
-
console.warn(
|
|
628
|
-
`Could not determine the file extension for the file at ${pathToDependencyFromDirectory}`
|
|
629
|
-
);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
return pathToDependencyFromDirectory;
|
|
633
|
-
}
|
|
634
|
-
);
|
|
635
|
-
const moduleDependencies = importedPathsRelativeToDirectory.filter(
|
|
636
|
-
(dependencyPath) => !dependencyPath.startsWith(".") && !import_node_path6.default.isAbsolute(dependencyPath)
|
|
637
|
-
);
|
|
638
|
-
const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
|
|
639
|
-
(dependencyPath) => dependencyPath.startsWith(".") || import_node_path6.default.isAbsolute(dependencyPath)
|
|
640
|
-
);
|
|
641
|
-
return {
|
|
642
|
-
dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
|
|
643
|
-
moduleDependencies
|
|
644
|
-
};
|
|
645
|
-
};
|
|
646
|
-
const updateModuleDependenciesInGraph = async (moduleFilePath) => {
|
|
647
|
-
const module2 = graph[moduleFilePath] ?? {
|
|
648
|
-
path: moduleFilePath,
|
|
649
|
-
dependencyPaths: [],
|
|
650
|
-
dependentPaths: [],
|
|
651
|
-
moduleDependencies: []
|
|
652
|
-
};
|
|
653
|
-
const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
|
|
654
|
-
module2.moduleDependencies = moduleDependencies;
|
|
655
|
-
for (const dependencyPath of module2.dependencyPaths) {
|
|
656
|
-
if (newDependencyPaths.includes(dependencyPath))
|
|
657
|
-
continue;
|
|
658
|
-
const dependencyModule = graph[dependencyPath];
|
|
659
|
-
if (dependencyModule !== void 0) {
|
|
660
|
-
dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter(
|
|
661
|
-
(dependentPath) => dependentPath !== moduleFilePath
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
module2.dependencyPaths = newDependencyPaths;
|
|
666
|
-
for (const dependencyPath of newDependencyPaths) {
|
|
667
|
-
const dependencyModule = graph[dependencyPath];
|
|
668
|
-
if (dependencyModule !== void 0 && !dependencyModule.dependentPaths.includes(moduleFilePath)) {
|
|
669
|
-
dependencyModule.dependentPaths.push(moduleFilePath);
|
|
670
|
-
} else {
|
|
671
|
-
graph[dependencyPath] = {
|
|
672
|
-
path: dependencyPath,
|
|
673
|
-
moduleDependencies: [],
|
|
674
|
-
dependencyPaths: [],
|
|
675
|
-
dependentPaths: [moduleFilePath]
|
|
676
|
-
};
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
graph[moduleFilePath] = module2;
|
|
680
|
-
};
|
|
681
|
-
for (const filePath of modulePaths) {
|
|
682
|
-
await updateModuleDependenciesInGraph(filePath);
|
|
683
|
-
}
|
|
684
|
-
const removeModuleFromGraph = (filePath) => {
|
|
685
|
-
const module2 = graph[filePath];
|
|
686
|
-
if (module2) {
|
|
687
|
-
for (const dependencyPath of module2.dependencyPaths) {
|
|
688
|
-
if (graph[dependencyPath]) {
|
|
689
|
-
graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter(
|
|
690
|
-
(dependentPath) => dependentPath !== filePath
|
|
691
|
-
);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
delete graph[filePath];
|
|
695
|
-
}
|
|
696
|
-
};
|
|
697
|
-
return [
|
|
698
|
-
graph,
|
|
699
|
-
async (event, pathToModified) => {
|
|
700
|
-
switch (event) {
|
|
701
|
-
case "change":
|
|
702
|
-
if (isJavascriptModule(pathToModified)) {
|
|
703
|
-
await updateModuleDependenciesInGraph(pathToModified);
|
|
704
|
-
}
|
|
705
|
-
break;
|
|
706
|
-
case "add":
|
|
707
|
-
if (isJavascriptModule(pathToModified)) {
|
|
708
|
-
await updateModuleDependenciesInGraph(pathToModified);
|
|
709
|
-
}
|
|
710
|
-
break;
|
|
711
|
-
case "addDir": {
|
|
712
|
-
const filesInsideAddedDirectory = await readAllFilesInsideDirectory(pathToModified);
|
|
713
|
-
const modulesInsideAddedDirectory = filesInsideAddedDirectory.filter(isJavascriptModule);
|
|
714
|
-
for await (const filePath of modulesInsideAddedDirectory) {
|
|
715
|
-
await updateModuleDependenciesInGraph(filePath);
|
|
716
|
-
}
|
|
717
|
-
break;
|
|
718
|
-
}
|
|
719
|
-
case "unlink":
|
|
720
|
-
if (isJavascriptModule(pathToModified)) {
|
|
721
|
-
removeModuleFromGraph(pathToModified);
|
|
722
|
-
}
|
|
723
|
-
break;
|
|
724
|
-
case "unlinkDir": {
|
|
725
|
-
const filesInsideDeletedDirectory = await readAllFilesInsideDirectory(pathToModified);
|
|
726
|
-
const modulesInsideDeletedDirectory = filesInsideDeletedDirectory.filter(isJavascriptModule);
|
|
727
|
-
for await (const filePath of modulesInsideDeletedDirectory) {
|
|
728
|
-
removeModuleFromGraph(filePath);
|
|
729
|
-
}
|
|
730
|
-
break;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
},
|
|
734
|
-
{
|
|
735
|
-
resolveDependentsOf: function resolveDependentsOf(pathToModule) {
|
|
736
|
-
const moduleEntry = graph[pathToModule];
|
|
737
|
-
const dependentPaths = [];
|
|
738
|
-
if (moduleEntry) {
|
|
739
|
-
for (const dependentPath of moduleEntry.dependentPaths) {
|
|
740
|
-
const dependentsOfDependent = resolveDependentsOf(dependentPath);
|
|
741
|
-
dependentPaths.push(...dependentsOfDependent);
|
|
742
|
-
dependentPaths.push(dependentPath);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
return dependentPaths;
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
];
|
|
749
|
-
};
|
|
750
|
-
|
|
751
|
-
// src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts
|
|
752
|
-
var setupHotreloading = async (devServer2, emailDirRelativePath) => {
|
|
753
|
-
let clients = [];
|
|
754
|
-
const io = new import_socket.Server(devServer2);
|
|
755
|
-
io.on("connection", (client) => {
|
|
756
|
-
clients.push(client);
|
|
757
|
-
client.on("disconnect", () => {
|
|
758
|
-
clients = clients.filter((item) => item !== client);
|
|
759
|
-
});
|
|
760
|
-
});
|
|
761
|
-
let changes = [];
|
|
762
|
-
const reload = (0, import_debounce.default)(() => {
|
|
763
|
-
clients.forEach((client) => {
|
|
764
|
-
client.emit("reload", changes);
|
|
765
|
-
});
|
|
766
|
-
changes = [];
|
|
767
|
-
}, 150);
|
|
768
|
-
const absolutePathToEmailsDirectory = import_node_path7.default.resolve(
|
|
769
|
-
process.cwd(),
|
|
770
|
-
emailDirRelativePath
|
|
771
|
-
);
|
|
772
|
-
const [dependencyGraph, updateDependencyGraph, { resolveDependentsOf }] = await createDependencyGraph(absolutePathToEmailsDirectory);
|
|
773
|
-
const watcher = (0, import_chokidar.watch)("", {
|
|
774
|
-
ignoreInitial: true,
|
|
775
|
-
cwd: absolutePathToEmailsDirectory
|
|
776
|
-
});
|
|
777
|
-
const getFilesOutsideEmailsDirectory = () => Object.keys(dependencyGraph).filter(
|
|
778
|
-
(p) => import_node_path7.default.relative(absolutePathToEmailsDirectory, p).startsWith("..")
|
|
779
|
-
);
|
|
780
|
-
let filesOutsideEmailsDirectory = getFilesOutsideEmailsDirectory();
|
|
781
|
-
for (const p of filesOutsideEmailsDirectory) {
|
|
782
|
-
watcher.add(p);
|
|
783
|
-
}
|
|
784
|
-
const exit = async () => {
|
|
785
|
-
await watcher.close();
|
|
786
|
-
};
|
|
787
|
-
process.on("SIGINT", exit);
|
|
788
|
-
process.on("uncaughtException", exit);
|
|
789
|
-
watcher.on("all", async (event, relativePathToChangeTarget) => {
|
|
790
|
-
const file = relativePathToChangeTarget.split(import_node_path7.default.sep);
|
|
791
|
-
if (file.length === 0) {
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
|
-
const pathToChangeTarget = import_node_path7.default.resolve(
|
|
795
|
-
absolutePathToEmailsDirectory,
|
|
796
|
-
relativePathToChangeTarget
|
|
797
|
-
);
|
|
798
|
-
await updateDependencyGraph(event, pathToChangeTarget);
|
|
799
|
-
const newFilesOutsideEmailsDirectory = getFilesOutsideEmailsDirectory();
|
|
800
|
-
for (const p of filesOutsideEmailsDirectory) {
|
|
801
|
-
if (!newFilesOutsideEmailsDirectory.includes(p)) {
|
|
802
|
-
watcher.unwatch(p);
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
for (const p of newFilesOutsideEmailsDirectory) {
|
|
806
|
-
if (!filesOutsideEmailsDirectory.includes(p)) {
|
|
807
|
-
watcher.add(p);
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
filesOutsideEmailsDirectory = newFilesOutsideEmailsDirectory;
|
|
811
|
-
changes.push({
|
|
812
|
-
event,
|
|
813
|
-
filename: relativePathToChangeTarget
|
|
814
|
-
});
|
|
815
|
-
for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
|
|
816
|
-
changes.push({
|
|
817
|
-
event: "change",
|
|
818
|
-
filename: import_node_path7.default.relative(absolutePathToEmailsDirectory, dependentPath)
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
reload();
|
|
822
|
-
});
|
|
823
|
-
return watcher;
|
|
824
|
-
};
|
|
825
|
-
|
|
826
|
-
// src/cli/commands/build.ts
|
|
827
|
-
var buildPreviewApp = (absoluteDirectory) => {
|
|
828
|
-
return new Promise((resolve, reject) => {
|
|
829
|
-
const nextBuild = (0, import_node_child_process.spawn)("npm", ["run", "build"], {
|
|
830
|
-
cwd: absoluteDirectory,
|
|
831
|
-
shell: true
|
|
832
|
-
});
|
|
833
|
-
nextBuild.stdout.pipe(process.stdout);
|
|
834
|
-
nextBuild.stderr.pipe(process.stderr);
|
|
835
|
-
nextBuild.on("close", (code) => {
|
|
836
|
-
if (code === 0) {
|
|
837
|
-
resolve();
|
|
838
|
-
} else {
|
|
839
|
-
reject(
|
|
840
|
-
new Error(
|
|
841
|
-
`Unable to build the Next app and it exited with code: ${code}`
|
|
842
|
-
)
|
|
843
|
-
);
|
|
844
|
-
}
|
|
845
|
-
});
|
|
846
|
-
});
|
|
847
|
-
};
|
|
848
|
-
var setNextEnvironmentVariablesForBuild = async (emailsDirRelativePath, builtPreviewAppPath) => {
|
|
849
|
-
const nextConfigContents = `
|
|
850
|
-
const path = require('path');
|
|
851
|
-
const emailsDirRelativePath = path.normalize('${emailsDirRelativePath}');
|
|
852
|
-
const userProjectLocation = path.resolve(process.cwd(), '../');
|
|
853
|
-
/** @type {import('next').NextConfig} */
|
|
854
|
-
module.exports = {
|
|
855
|
-
env: {
|
|
856
|
-
NEXT_PUBLIC_IS_BUILDING: 'true',
|
|
857
|
-
EMAILS_DIR_RELATIVE_PATH: emailsDirRelativePath,
|
|
858
|
-
EMAILS_DIR_ABSOLUTE_PATH: path.resolve(userProjectLocation, emailsDirRelativePath),
|
|
859
|
-
USER_PROJECT_LOCATION: userProjectLocation
|
|
860
|
-
},
|
|
861
|
-
// this is needed so that the code for building emails works properly
|
|
862
|
-
webpack: (
|
|
863
|
-
/** @type {import('webpack').Configuration & { externals: string[] }} */
|
|
864
|
-
config,
|
|
865
|
-
{ isServer }
|
|
866
|
-
) => {
|
|
867
|
-
if (isServer) {
|
|
868
|
-
config.externals.push('esbuild');
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
return config;
|
|
872
|
-
},
|
|
873
|
-
typescript: {
|
|
874
|
-
ignoreBuildErrors: true
|
|
875
|
-
},
|
|
876
|
-
eslint: {
|
|
877
|
-
ignoreDuringBuilds: true
|
|
878
|
-
},
|
|
879
|
-
experimental: {
|
|
880
|
-
webpackBuildWorker: true
|
|
881
|
-
},
|
|
882
|
-
}`;
|
|
883
|
-
await import_node_fs5.default.promises.writeFile(
|
|
884
|
-
import_node_path8.default.resolve(builtPreviewAppPath, "./next.config.js"),
|
|
885
|
-
nextConfigContents,
|
|
886
|
-
"utf8"
|
|
887
|
-
);
|
|
888
|
-
};
|
|
889
|
-
var getEmailSlugsFromEmailDirectory = (emailDirectory, emailsDirectoryAbsolutePath) => {
|
|
890
|
-
const directoryPathRelativeToEmailsDirectory = emailDirectory.absolutePath.replace(emailsDirectoryAbsolutePath, "").trim();
|
|
891
|
-
const slugs = [];
|
|
892
|
-
emailDirectory.emailFilenames.forEach(
|
|
893
|
-
(filename) => slugs.push(
|
|
894
|
-
import_node_path8.default.join(directoryPathRelativeToEmailsDirectory, filename).split(import_node_path8.default.sep).filter((segment) => segment.length > 0)
|
|
895
|
-
)
|
|
896
|
-
);
|
|
897
|
-
emailDirectory.subDirectories.forEach((directory) => {
|
|
898
|
-
slugs.push(
|
|
899
|
-
...getEmailSlugsFromEmailDirectory(
|
|
900
|
-
directory,
|
|
901
|
-
emailsDirectoryAbsolutePath
|
|
902
|
-
)
|
|
903
|
-
);
|
|
904
|
-
});
|
|
905
|
-
return slugs;
|
|
906
|
-
};
|
|
907
|
-
var forceSSGForEmailPreviews = async (emailsDirPath, builtPreviewAppPath) => {
|
|
908
|
-
const emailDirectoryMetadata = (
|
|
909
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
910
|
-
await getEmailsDirectoryMetadata(emailsDirPath)
|
|
911
|
-
);
|
|
912
|
-
const parameters = getEmailSlugsFromEmailDirectory(
|
|
913
|
-
emailDirectoryMetadata,
|
|
914
|
-
emailsDirPath
|
|
915
|
-
).map((slug) => ({ slug }));
|
|
916
|
-
const removeForceDynamic = async (filePath) => {
|
|
917
|
-
const contents = await import_node_fs5.default.promises.readFile(filePath, "utf8");
|
|
918
|
-
await import_node_fs5.default.promises.writeFile(
|
|
919
|
-
filePath,
|
|
920
|
-
contents.replace("export const dynamic = 'force-dynamic';", ""),
|
|
921
|
-
"utf8"
|
|
922
|
-
);
|
|
923
|
-
};
|
|
924
|
-
await removeForceDynamic(
|
|
925
|
-
import_node_path8.default.resolve(builtPreviewAppPath, "./src/app/layout.tsx")
|
|
926
|
-
);
|
|
927
|
-
await removeForceDynamic(
|
|
928
|
-
import_node_path8.default.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx")
|
|
929
|
-
);
|
|
930
|
-
await import_node_fs5.default.promises.appendFile(
|
|
931
|
-
import_node_path8.default.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx"),
|
|
932
|
-
`
|
|
933
|
-
|
|
934
|
-
export function generateStaticParams() {
|
|
935
|
-
return Promise.resolve(
|
|
936
|
-
${JSON.stringify(parameters)}
|
|
937
|
-
);
|
|
938
|
-
}`,
|
|
939
|
-
"utf8"
|
|
940
|
-
);
|
|
941
|
-
};
|
|
942
|
-
var updatePackageJson = async (builtPreviewAppPath) => {
|
|
943
|
-
const packageJsonPath = import_node_path8.default.resolve(builtPreviewAppPath, "./package.json");
|
|
944
|
-
const packageJson = JSON.parse(
|
|
945
|
-
await import_node_fs5.default.promises.readFile(packageJsonPath, "utf8")
|
|
946
|
-
);
|
|
947
|
-
packageJson.scripts.build = "next build";
|
|
948
|
-
packageJson.scripts.start = "next start";
|
|
949
|
-
packageJson.name = "preview-server";
|
|
950
|
-
delete packageJson.devDependencies["@react-email/render"];
|
|
951
|
-
delete packageJson.devDependencies["@react-email/components"];
|
|
952
|
-
delete packageJson.scripts.prepare;
|
|
953
|
-
await import_node_fs5.default.promises.writeFile(
|
|
954
|
-
packageJsonPath,
|
|
955
|
-
JSON.stringify(packageJson),
|
|
956
|
-
"utf8"
|
|
957
|
-
);
|
|
958
|
-
};
|
|
959
|
-
var npmInstall = async (builtPreviewAppPath, packageManager) => {
|
|
960
|
-
return new Promise((resolve, reject) => {
|
|
961
|
-
const childProc = (0, import_node_child_process.spawn)(
|
|
962
|
-
packageManager,
|
|
963
|
-
[
|
|
964
|
-
"install",
|
|
965
|
-
packageManager === "deno" ? "" : "--include=dev",
|
|
966
|
-
packageManager === "deno" ? "--quiet" : "--silent"
|
|
967
|
-
],
|
|
968
|
-
{
|
|
969
|
-
cwd: builtPreviewAppPath,
|
|
970
|
-
shell: true
|
|
971
|
-
}
|
|
972
|
-
);
|
|
973
|
-
childProc.stdout.pipe(process.stdout);
|
|
974
|
-
childProc.stderr.pipe(process.stderr);
|
|
975
|
-
childProc.on("close", (code) => {
|
|
976
|
-
if (code === 0) {
|
|
977
|
-
resolve();
|
|
978
|
-
} else {
|
|
979
|
-
reject(
|
|
980
|
-
new Error(
|
|
981
|
-
`Unable to install the dependencies and it exited with code: ${code}`
|
|
982
|
-
)
|
|
983
|
-
);
|
|
984
|
-
}
|
|
985
|
-
});
|
|
986
|
-
});
|
|
987
|
-
};
|
|
988
|
-
var build = async ({
|
|
989
|
-
dir: emailsDirRelativePath,
|
|
990
|
-
packageManager
|
|
991
|
-
}) => {
|
|
992
|
-
try {
|
|
993
|
-
const spinner = (0, import_ora2.default)({
|
|
994
|
-
text: "Starting build process...",
|
|
995
|
-
prefixText: " "
|
|
996
|
-
}).start();
|
|
997
|
-
registerSpinnerAutostopping(spinner);
|
|
998
|
-
spinner.text = `Checking if ${emailsDirRelativePath} folder exists`;
|
|
999
|
-
if (!import_node_fs5.default.existsSync(emailsDirRelativePath)) {
|
|
1000
|
-
process.exit(1);
|
|
1001
|
-
}
|
|
1002
|
-
const emailsDirPath = import_node_path8.default.join(process.cwd(), emailsDirRelativePath);
|
|
1003
|
-
const staticPath = import_node_path8.default.join(emailsDirPath, "static");
|
|
1004
|
-
const builtPreviewAppPath = import_node_path8.default.join(process.cwd(), ".react-email");
|
|
1005
|
-
if (import_node_fs5.default.existsSync(builtPreviewAppPath)) {
|
|
1006
|
-
spinner.text = "Deleting pre-existing `.react-email` folder";
|
|
1007
|
-
await import_node_fs5.default.promises.rm(builtPreviewAppPath, { recursive: true });
|
|
1008
|
-
}
|
|
1009
|
-
spinner.text = "Copying preview app from CLI to `.react-email`";
|
|
1010
|
-
await import_node_fs5.default.promises.cp(cliPackageLocation, builtPreviewAppPath, {
|
|
1011
|
-
recursive: true,
|
|
1012
|
-
filter: (source) => {
|
|
1013
|
-
return !/(\/|\\)cli(\/|\\)?/.test(source) && !/(\/|\\)\.next(\/|\\)?/.test(source) && !/(\/|\\)\.turbo(\/|\\)?/.test(source) && !/(\/|\\)node_modules(\/|\\)?$/.test(source);
|
|
1014
|
-
}
|
|
1015
|
-
});
|
|
1016
|
-
if (import_node_fs5.default.existsSync(staticPath)) {
|
|
1017
|
-
spinner.text = "Copying `static` folder into `.react-email/public/static`";
|
|
1018
|
-
const builtStaticDirectory = import_node_path8.default.resolve(
|
|
1019
|
-
builtPreviewAppPath,
|
|
1020
|
-
"./public/static"
|
|
1021
|
-
);
|
|
1022
|
-
await import_node_fs5.default.promises.cp(staticPath, builtStaticDirectory, {
|
|
1023
|
-
recursive: true
|
|
1024
|
-
});
|
|
1025
|
-
}
|
|
1026
|
-
spinner.text = "Setting Next environment variables for preview app to work properly";
|
|
1027
|
-
await setNextEnvironmentVariablesForBuild(
|
|
1028
|
-
emailsDirRelativePath,
|
|
1029
|
-
builtPreviewAppPath
|
|
1030
|
-
);
|
|
1031
|
-
spinner.text = "Setting server side generation for the email preview pages";
|
|
1032
|
-
await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
|
|
1033
|
-
spinner.text = "Updating package.json's build and start scripts";
|
|
1034
|
-
await updatePackageJson(builtPreviewAppPath);
|
|
1035
|
-
spinner.text = "Installing dependencies on `.react-email`";
|
|
1036
|
-
await npmInstall(builtPreviewAppPath, packageManager);
|
|
1037
|
-
spinner.stopAndPersist({
|
|
1038
|
-
text: "Successfully prepared `.react-email` for `next build`",
|
|
1039
|
-
symbol: import_log_symbols3.default.success
|
|
1040
|
-
});
|
|
1041
|
-
await buildPreviewApp(builtPreviewAppPath);
|
|
1042
|
-
} catch (error) {
|
|
1043
|
-
console.log(error);
|
|
1044
|
-
process.exit(1);
|
|
1045
|
-
}
|
|
1046
|
-
};
|
|
1047
|
-
|
|
1048
|
-
// src/cli/commands/dev.ts
|
|
1049
|
-
var import_node_fs6 = __toESM(require("fs"));
|
|
1050
|
-
var dev = async ({ dir: emailsDirRelativePath, port }) => {
|
|
1051
|
-
try {
|
|
1052
|
-
if (!import_node_fs6.default.existsSync(emailsDirRelativePath)) {
|
|
1053
|
-
console.error(`Missing ${emailsDirRelativePath} folder`);
|
|
1054
|
-
process.exit(1);
|
|
1055
|
-
}
|
|
1056
|
-
const devServer2 = await startDevServer(
|
|
1057
|
-
emailsDirRelativePath,
|
|
1058
|
-
emailsDirRelativePath,
|
|
1059
|
-
// defaults to ./emails/static for the static files that are served to the preview
|
|
1060
|
-
Number.parseInt(port)
|
|
1061
|
-
);
|
|
1062
|
-
await setupHotreloading(devServer2, emailsDirRelativePath);
|
|
1063
|
-
} catch (error) {
|
|
1064
|
-
console.log(error);
|
|
1065
|
-
process.exit(1);
|
|
1066
|
-
}
|
|
1067
|
-
};
|
|
1068
|
-
|
|
1069
|
-
// src/cli/commands/export.ts
|
|
1070
|
-
var import_node_fs8 = __toESM(require("fs"));
|
|
1071
|
-
var import_node_path10 = __toESM(require("path"));
|
|
1072
|
-
var import_esbuild = require("esbuild");
|
|
1073
|
-
var import_glob = require("glob");
|
|
1074
|
-
var import_log_symbols4 = __toESM(require("log-symbols"));
|
|
1075
|
-
var import_normalize_path = __toESM(require("normalize-path"));
|
|
1076
|
-
var import_ora3 = __toESM(require("ora"));
|
|
1077
|
-
|
|
1078
|
-
// src/utils/esbuild/renderring-utilities-exporter.ts
|
|
1079
|
-
var import_node_fs7 = require("fs");
|
|
1080
|
-
var import_node_path9 = __toESM(require("path"));
|
|
1081
|
-
|
|
1082
|
-
// src/utils/esbuild/escape-string-for-regex.ts
|
|
1083
|
-
function escapeStringForRegex(string) {
|
|
1084
|
-
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
// src/utils/esbuild/renderring-utilities-exporter.ts
|
|
1088
|
-
var renderingUtilitiesExporter = (emailTemplates) => ({
|
|
1089
|
-
name: "rendering-utilities-exporter",
|
|
1090
|
-
setup: (b) => {
|
|
1091
|
-
b.onLoad(
|
|
1092
|
-
{
|
|
1093
|
-
filter: new RegExp(
|
|
1094
|
-
emailTemplates.map((emailPath) => escapeStringForRegex(emailPath)).join("|")
|
|
1095
|
-
)
|
|
1096
|
-
},
|
|
1097
|
-
async ({ path: pathToFile }) => {
|
|
1098
|
-
return {
|
|
1099
|
-
contents: `${await import_node_fs7.promises.readFile(pathToFile, "utf8")};
|
|
1100
|
-
export { render } from 'react-email-module-that-will-export-render'
|
|
1101
|
-
export { createElement as reactEmailCreateReactElement } from 'react';
|
|
1102
|
-
`,
|
|
1103
|
-
loader: import_node_path9.default.extname(pathToFile).slice(1)
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
);
|
|
1107
|
-
b.onResolve(
|
|
1108
|
-
{ filter: /^react-email-module-that-will-export-render$/ },
|
|
1109
|
-
async (args) => {
|
|
1110
|
-
const options = {
|
|
1111
|
-
kind: "import-statement",
|
|
1112
|
-
importer: args.importer,
|
|
1113
|
-
resolveDir: args.resolveDir,
|
|
1114
|
-
namespace: args.namespace
|
|
1115
|
-
};
|
|
1116
|
-
let result = await b.resolve("@react-email/render", options);
|
|
1117
|
-
if (result.errors.length === 0) {
|
|
1118
|
-
return result;
|
|
1119
|
-
}
|
|
1120
|
-
result = await b.resolve("@react-email/components", options);
|
|
1121
|
-
if (result.errors.length > 0 && result.errors[0]) {
|
|
1122
|
-
result.errors[0].text = "Failed trying to import `render` from either `@react-email/render` or `@react-email/components` to be able to render your email template.\n Maybe you don't have either of them installed?";
|
|
1123
|
-
}
|
|
1124
|
-
return result;
|
|
1125
|
-
}
|
|
1126
|
-
);
|
|
1127
|
-
}
|
|
1128
|
-
});
|
|
1129
|
-
|
|
1130
|
-
// src/cli/commands/export.ts
|
|
1131
|
-
var getEmailTemplatesFromDirectory = (emailDirectory) => {
|
|
1132
|
-
const templatePaths = [];
|
|
1133
|
-
emailDirectory.emailFilenames.forEach(
|
|
1134
|
-
(filename) => templatePaths.push(import_node_path10.default.join(emailDirectory.absolutePath, filename))
|
|
1135
|
-
);
|
|
1136
|
-
emailDirectory.subDirectories.forEach((directory) => {
|
|
1137
|
-
templatePaths.push(...getEmailTemplatesFromDirectory(directory));
|
|
1138
|
-
});
|
|
1139
|
-
return templatePaths;
|
|
1140
|
-
};
|
|
1141
|
-
var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirectoryPath, options) => {
|
|
1142
|
-
if (import_node_fs8.default.existsSync(pathToWhereEmailMarkupShouldBeDumped)) {
|
|
1143
|
-
import_node_fs8.default.rmSync(pathToWhereEmailMarkupShouldBeDumped, { recursive: true });
|
|
1144
|
-
}
|
|
1145
|
-
let spinner;
|
|
1146
|
-
if (!options.silent) {
|
|
1147
|
-
spinner = (0, import_ora3.default)("Preparing files...\n").start();
|
|
1148
|
-
registerSpinnerAutostopping(spinner);
|
|
1149
|
-
}
|
|
1150
|
-
const emailsDirectoryMetadata = await getEmailsDirectoryMetadata(
|
|
1151
|
-
import_node_path10.default.resolve(process.cwd(), emailsDirectoryPath),
|
|
1152
|
-
true
|
|
1153
|
-
);
|
|
1154
|
-
if (typeof emailsDirectoryMetadata === "undefined") {
|
|
1155
|
-
if (spinner) {
|
|
1156
|
-
spinner.stopAndPersist({
|
|
1157
|
-
symbol: import_log_symbols4.default.error,
|
|
1158
|
-
text: `Could not find the directory at ${emailsDirectoryPath}`
|
|
1159
|
-
});
|
|
1160
|
-
}
|
|
1161
|
-
return;
|
|
1162
|
-
}
|
|
1163
|
-
const allTemplates = getEmailTemplatesFromDirectory(emailsDirectoryMetadata);
|
|
1164
|
-
try {
|
|
1165
|
-
await (0, import_esbuild.build)({
|
|
1166
|
-
bundle: true,
|
|
1167
|
-
entryPoints: allTemplates,
|
|
1168
|
-
plugins: [renderingUtilitiesExporter(allTemplates)],
|
|
1169
|
-
platform: "node",
|
|
1170
|
-
format: "cjs",
|
|
1171
|
-
loader: { ".js": "jsx" },
|
|
1172
|
-
outExtension: { ".js": ".cjs" },
|
|
1173
|
-
jsx: "transform",
|
|
1174
|
-
write: true,
|
|
1175
|
-
outdir: pathToWhereEmailMarkupShouldBeDumped
|
|
1176
|
-
});
|
|
1177
|
-
} catch (exception) {
|
|
1178
|
-
const buildFailure = exception;
|
|
1179
|
-
if (spinner) {
|
|
1180
|
-
spinner.stopAndPersist({
|
|
1181
|
-
symbol: import_log_symbols4.default.error,
|
|
1182
|
-
text: "Failed to build emails"
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
process.exit(1);
|
|
1186
|
-
}
|
|
1187
|
-
if (spinner) {
|
|
1188
|
-
spinner.succeed();
|
|
1189
|
-
}
|
|
1190
|
-
const allBuiltTemplates = import_glob.glob.sync(
|
|
1191
|
-
(0, import_normalize_path.default)(`${pathToWhereEmailMarkupShouldBeDumped}/**/*.cjs`),
|
|
1192
|
-
{
|
|
1193
|
-
absolute: true
|
|
1194
|
-
}
|
|
1195
|
-
);
|
|
1196
|
-
for await (const template of allBuiltTemplates) {
|
|
1197
|
-
try {
|
|
1198
|
-
if (spinner) {
|
|
1199
|
-
spinner.text = `rendering ${template.split("/").pop()}`;
|
|
1200
|
-
spinner.render();
|
|
1201
|
-
}
|
|
1202
|
-
delete require.cache[template];
|
|
1203
|
-
const emailModule = require(template);
|
|
1204
|
-
const rendered = await emailModule.render(
|
|
1205
|
-
emailModule.reactEmailCreateReactElement(emailModule.default, {}),
|
|
1206
|
-
options
|
|
1207
|
-
);
|
|
1208
|
-
const htmlPath = template.replace(
|
|
1209
|
-
".cjs",
|
|
1210
|
-
options.plainText ? ".txt" : ".html"
|
|
1211
|
-
);
|
|
1212
|
-
(0, import_node_fs8.writeFileSync)(htmlPath, rendered);
|
|
1213
|
-
(0, import_node_fs8.unlinkSync)(template);
|
|
1214
|
-
} catch (exception) {
|
|
1215
|
-
if (spinner) {
|
|
1216
|
-
spinner.stopAndPersist({
|
|
1217
|
-
symbol: import_log_symbols4.default.error,
|
|
1218
|
-
text: `failed when rendering ${template.split("/").pop()}`
|
|
1219
|
-
});
|
|
1220
|
-
}
|
|
1221
|
-
console.error(exception);
|
|
1222
|
-
process.exit(1);
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
if (spinner) {
|
|
1226
|
-
spinner.succeed("Rendered all files");
|
|
1227
|
-
spinner.text = "Copying static files";
|
|
1228
|
-
spinner.render();
|
|
1229
|
-
}
|
|
1230
|
-
const staticDirectoryPath = import_node_path10.default.join(emailsDirectoryPath, "static");
|
|
1231
|
-
if (import_node_fs8.default.existsSync(staticDirectoryPath)) {
|
|
1232
|
-
const pathToDumpStaticFilesInto = import_node_path10.default.join(
|
|
1233
|
-
pathToWhereEmailMarkupShouldBeDumped,
|
|
1234
|
-
"static"
|
|
1235
|
-
);
|
|
1236
|
-
if (import_node_fs8.default.existsSync(pathToDumpStaticFilesInto))
|
|
1237
|
-
await import_node_fs8.default.promises.rm(pathToDumpStaticFilesInto, { recursive: true });
|
|
1238
|
-
try {
|
|
1239
|
-
await import_node_fs8.default.promises.cp(staticDirectoryPath, pathToDumpStaticFilesInto, {
|
|
1240
|
-
recursive: true
|
|
1241
|
-
});
|
|
1242
|
-
} catch (exception) {
|
|
1243
|
-
console.error(exception);
|
|
1244
|
-
if (spinner) {
|
|
1245
|
-
spinner.stopAndPersist({
|
|
1246
|
-
symbol: import_log_symbols4.default.error,
|
|
1247
|
-
text: "Failed to copy static files"
|
|
1248
|
-
});
|
|
1249
|
-
}
|
|
1250
|
-
console.error(
|
|
1251
|
-
`Something went wrong while copying the file to ${pathToWhereEmailMarkupShouldBeDumped}/static, ${exception}`
|
|
1252
|
-
);
|
|
1253
|
-
process.exit(1);
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
if (spinner && !options.silent) {
|
|
1257
|
-
spinner.succeed();
|
|
1258
|
-
const fileTree = await tree(pathToWhereEmailMarkupShouldBeDumped, 4);
|
|
1259
|
-
console.log(fileTree);
|
|
1260
|
-
spinner.stopAndPersist({
|
|
1261
|
-
symbol: import_log_symbols4.default.success,
|
|
1262
|
-
text: "Successfully exported emails"
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
};
|
|
1266
|
-
|
|
1267
|
-
// src/cli/commands/start.ts
|
|
1268
|
-
var import_node_child_process2 = require("child_process");
|
|
1269
|
-
var import_node_fs9 = __toESM(require("fs"));
|
|
1270
|
-
var import_node_path11 = __toESM(require("path"));
|
|
1271
|
-
var start = async () => {
|
|
1272
|
-
try {
|
|
1273
|
-
const usersProjectLocation = process.cwd();
|
|
1274
|
-
const builtPreviewPath = import_node_path11.default.resolve(
|
|
1275
|
-
usersProjectLocation,
|
|
1276
|
-
"./.react-email"
|
|
1277
|
-
);
|
|
1278
|
-
if (!import_node_fs9.default.existsSync(builtPreviewPath)) {
|
|
1279
|
-
console.error(
|
|
1280
|
-
"Could not find .react-email, maybe you haven't ran email build?"
|
|
1281
|
-
);
|
|
1282
|
-
process.exit(1);
|
|
1283
|
-
}
|
|
1284
|
-
const nextStart = (0, import_node_child_process2.spawn)("npm", ["start"], {
|
|
1285
|
-
cwd: builtPreviewPath,
|
|
1286
|
-
stdio: "inherit"
|
|
1287
|
-
});
|
|
1288
|
-
process.on("SIGINT", () => {
|
|
1289
|
-
nextStart.kill("SIGINT");
|
|
1290
|
-
});
|
|
1291
|
-
nextStart.on("exit", (code) => {
|
|
1292
|
-
process.exit(code ?? 0);
|
|
1293
|
-
});
|
|
1294
|
-
} catch (error) {
|
|
1295
|
-
console.log(error);
|
|
1296
|
-
process.exit(1);
|
|
1297
|
-
}
|
|
1298
|
-
};
|
|
1299
|
-
|
|
1300
|
-
// src/cli/index.ts
|
|
1301
|
-
var PACKAGE_NAME = "react-email";
|
|
1302
|
-
import_commander.program.name(PACKAGE_NAME).description("A live preview of your emails right in your browser").version(package_default.version);
|
|
1303
|
-
import_commander.program.command("dev").description("Starts the preview email development app").option("-d, --dir <path>", "Directory with your email templates", "./emails").option("-p --port <port>", "Port to run dev server on", "3000").action(dev);
|
|
1304
|
-
import_commander.program.command("build").description("Copies the preview app for onto .react-email and builds it").option("-d, --dir <path>", "Directory with your email templates", "./emails").option(
|
|
1305
|
-
"-p --packageManager <name>",
|
|
1306
|
-
"Package name to use on installation on `.react-email`",
|
|
1307
|
-
"npm"
|
|
1308
|
-
).action(build);
|
|
1309
|
-
import_commander.program.command("start").description('Runs the built preview app that is inside of ".react-email"').action(start);
|
|
1310
|
-
import_commander.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(
|
|
1311
|
-
"-s, --silent",
|
|
1312
|
-
"To, or not to show a spinner with process information",
|
|
1313
|
-
false
|
|
1314
|
-
).action(
|
|
1315
|
-
({ outDir, pretty, plainText, silent, dir: srcDir }) => exportTemplates(outDir, srcDir, { pretty, silent, plainText })
|
|
1316
|
-
);
|
|
1317
|
-
import_commander.program.parse();
|