react-email 1.7.4 → 1.7.6
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/dist/package.json +1 -1
- package/dist/source/_preview/root.js +1 -1
- package/dist/source/commands/dev.d.ts +5 -1
- package/dist/source/commands/dev.js +25 -20
- package/dist/source/commands/export.d.ts +1 -1
- package/dist/source/commands/export.js +6 -4
- package/dist/source/index.js +6 -4
- package/dist/source/utils/watcher.d.ts +3 -3
- package/dist/source/utils/watcher.js +19 -14
- package/package.json +1 -1
- package/preview/emails/test.tsx +15 -0
- package/preview/package.json +2 -2
- package/source/_preview/root.ts +1 -1
- package/source/commands/dev.ts +31 -22
- package/source/commands/export.ts +7 -6
- package/source/index.ts +7 -5
- package/source/utils/watcher.ts +25 -24
package/dist/package.json
CHANGED
|
@@ -12,7 +12,7 @@ exports.root = [
|
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
title: 'package.json',
|
|
15
|
-
content: '{\n "name": "react-email-preview",\n "version": "0.0.
|
|
15
|
+
content: '{\n "name": "react-email-preview",\n "version": "0.0.10",\n "description": "The React Email preview application",\n "license": "MIT",\n "scripts": {\n "dev": "next dev",\n "build": "next build",\n "start": "next start",\n "lint": "next lint",\n "format:check": "prettier --check \\"**/*.{ts,tsx,md}\\"",\n "format": "prettier --write \\"**/*.{ts,tsx,md}\\""\n },\n "engines": {\n "node": ">=16.0.0"\n },\n "dependencies": {\n "@next/font": "13.0.4",\n "@radix-ui/colors": "0.1.8",\n "@radix-ui/react-collapsible": "1.0.1",\n "@radix-ui/react-popover": "1.0.2",\n "@radix-ui/react-slot": "1.0.1",\n "@radix-ui/react-toggle-group": "1.0.1",\n "@radix-ui/react-tooltip": "1.0.2",\n "@react-email/render": "0.0.6",\n "classnames": "2.3.2",\n "framer-motion": "8.4.6",\n "next": "13.0.4",\n "prism-react-renderer": "1.3.5",\n "react": "18.2.0",\n "react-dom": "18.2.0"\n },\n "devDependencies": {\n "@types/classnames": "2.3.1",\n "@types/node": "18.11.9",\n "@types/react": "18.0.25",\n "@types/react-dom": "18.0.9",\n "autoprefixer": "10.4.13",\n "postcss": "8.4.19",\n "tailwindcss": "3.2.4",\n "typescript": "4.9.3"\n }\n}\n',
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
title: 'postcss.config.js',
|
|
@@ -18,7 +18,9 @@ const ora_1 = __importDefault(require("ora"));
|
|
|
18
18
|
const read_pkg_1 = __importDefault(require("read-pkg"));
|
|
19
19
|
const shelljs_1 = __importDefault(require("shelljs"));
|
|
20
20
|
const styles_1 = require("../_preview/styles");
|
|
21
|
-
const dev = async () => {
|
|
21
|
+
const dev = async ({ dir }) => {
|
|
22
|
+
const emailDir = convertToAbsolutePath(dir);
|
|
23
|
+
const watcherInstance = (0, utils_1.createWatcherInstance)(emailDir);
|
|
22
24
|
try {
|
|
23
25
|
const hasReactEmailDirectory = (0, utils_1.checkDirectoryExist)(utils_1.REACT_EMAIL_ROOT);
|
|
24
26
|
let packageManager;
|
|
@@ -31,10 +33,10 @@ const dev = async () => {
|
|
|
31
33
|
if (hasReactEmailDirectory) {
|
|
32
34
|
const isUpToDate = await (0, utils_1.checkPackageIsUpToDate)();
|
|
33
35
|
if (isUpToDate) {
|
|
34
|
-
await Promise.all([generateEmailsPreview(), syncPkg()]);
|
|
36
|
+
await Promise.all([generateEmailsPreview(emailDir), syncPkg()]);
|
|
35
37
|
await installDependencies(packageManager);
|
|
36
38
|
shelljs_1.default.exec(`${packageManager} run dev`, { async: true });
|
|
37
|
-
(0, utils_1.watcher)();
|
|
39
|
+
(0, utils_1.watcher)(watcherInstance, emailDir);
|
|
38
40
|
return;
|
|
39
41
|
}
|
|
40
42
|
await fs_1.default.promises.rm(utils_1.REACT_EMAIL_ROOT, { recursive: true });
|
|
@@ -42,17 +44,18 @@ const dev = async () => {
|
|
|
42
44
|
await createBasicStructure();
|
|
43
45
|
await createAppDirectories();
|
|
44
46
|
await createAppFiles();
|
|
45
|
-
await Promise.all([generateEmailsPreview(), syncPkg()]);
|
|
47
|
+
await Promise.all([generateEmailsPreview(emailDir), syncPkg()]);
|
|
46
48
|
await installDependencies(packageManager);
|
|
47
49
|
shelljs_1.default.exec(`${packageManager} run dev`, { async: true });
|
|
48
|
-
(0, utils_1.watcher)();
|
|
50
|
+
(0, utils_1.watcher)(watcherInstance, emailDir);
|
|
49
51
|
}
|
|
50
52
|
catch (error) {
|
|
51
|
-
await
|
|
53
|
+
await watcherInstance.close();
|
|
52
54
|
shelljs_1.default.exit(1);
|
|
53
55
|
}
|
|
54
56
|
};
|
|
55
57
|
exports.dev = dev;
|
|
58
|
+
const convertToAbsolutePath = (dir) => path_1.default.isAbsolute(dir) ? dir : path_1.default.join(process.cwd(), dir);
|
|
56
59
|
const createBasicStructure = async () => {
|
|
57
60
|
try {
|
|
58
61
|
// Create `.react-email` directory
|
|
@@ -111,12 +114,12 @@ const createAppFiles = async () => {
|
|
|
111
114
|
throw new Error('Error creating app files');
|
|
112
115
|
}
|
|
113
116
|
};
|
|
114
|
-
const generateEmailsPreview = async () => {
|
|
117
|
+
const generateEmailsPreview = async (emailDir) => {
|
|
115
118
|
try {
|
|
116
119
|
const spinner = (0, ora_1.default)('Generating emails preview').start();
|
|
117
|
-
await createEmailPreviews();
|
|
118
|
-
await
|
|
119
|
-
await createComponents();
|
|
120
|
+
await createEmailPreviews(emailDir);
|
|
121
|
+
await createStaticFiles(emailDir);
|
|
122
|
+
await createComponents(emailDir);
|
|
120
123
|
spinner.stopAndPersist({
|
|
121
124
|
symbol: log_symbols_1.default.success,
|
|
122
125
|
text: 'Emails preview generated',
|
|
@@ -126,10 +129,10 @@ const generateEmailsPreview = async () => {
|
|
|
126
129
|
console.log({ error });
|
|
127
130
|
}
|
|
128
131
|
};
|
|
129
|
-
const createEmailPreviews = async () => {
|
|
130
|
-
const hasEmailsDirectory = (0, utils_1.checkDirectoryExist)(
|
|
132
|
+
const createEmailPreviews = async (emailDir) => {
|
|
133
|
+
const hasEmailsDirectory = (0, utils_1.checkDirectoryExist)(emailDir);
|
|
131
134
|
const isEmailsDirectoryEmpty = hasEmailsDirectory
|
|
132
|
-
? await (0, utils_1.checkEmptyDirectory)(
|
|
135
|
+
? await (0, utils_1.checkEmptyDirectory)(emailDir)
|
|
133
136
|
: true;
|
|
134
137
|
if (isEmailsDirectoryEmpty) {
|
|
135
138
|
}
|
|
@@ -137,30 +140,32 @@ const createEmailPreviews = async () => {
|
|
|
137
140
|
if (hasPackageEmailsDirectory) {
|
|
138
141
|
await fs_1.default.promises.rm(utils_1.PACKAGE_EMAILS_PATH, { recursive: true });
|
|
139
142
|
}
|
|
140
|
-
await (0, cpy_1.default)(
|
|
143
|
+
await (0, cpy_1.default)(path_1.default.join(emailDir, '*{.tsx,.jsx}'), utils_1.PACKAGE_EMAILS_PATH);
|
|
141
144
|
};
|
|
142
|
-
const
|
|
145
|
+
const createStaticFiles = async (emailDir) => {
|
|
143
146
|
const hasPackageStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.REACT_EMAIL_ROOT}/public/static`);
|
|
144
|
-
const
|
|
147
|
+
const staticDir = path_1.default.join(emailDir, 'static');
|
|
148
|
+
const hasStaticDirectory = (0, utils_1.checkDirectoryExist)(staticDir);
|
|
145
149
|
if (hasPackageStaticDirectory) {
|
|
146
150
|
await fs_1.default.promises.rm(`${utils_1.REACT_EMAIL_ROOT}/public/static`, {
|
|
147
151
|
recursive: true,
|
|
148
152
|
});
|
|
149
153
|
}
|
|
150
154
|
if (hasStaticDirectory) {
|
|
151
|
-
await (0, cpy_1.default)(
|
|
155
|
+
await (0, cpy_1.default)(staticDir, `${utils_1.REACT_EMAIL_ROOT}/public/static`);
|
|
152
156
|
}
|
|
153
157
|
};
|
|
154
|
-
const createComponents = async () => {
|
|
158
|
+
const createComponents = async (emailDir) => {
|
|
155
159
|
const hasPackageComponentsDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.PACKAGE_EMAILS_PATH}/components`);
|
|
156
|
-
const
|
|
160
|
+
const componentDir = path_1.default.join(emailDir, 'components');
|
|
161
|
+
const hasComponentsDirectory = (0, utils_1.checkDirectoryExist)(componentDir);
|
|
157
162
|
if (hasPackageComponentsDirectory) {
|
|
158
163
|
await fs_1.default.promises.rm(`${utils_1.PACKAGE_EMAILS_PATH}/components`, {
|
|
159
164
|
recursive: true,
|
|
160
165
|
});
|
|
161
166
|
}
|
|
162
167
|
if (hasComponentsDirectory) {
|
|
163
|
-
await (0, cpy_1.default)(
|
|
168
|
+
await (0, cpy_1.default)(componentDir, `${utils_1.PACKAGE_EMAILS_PATH}/components`);
|
|
164
169
|
}
|
|
165
170
|
};
|
|
166
171
|
const syncPkg = async () => {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Options } from '@react-email/render';
|
|
2
|
-
export declare const exportTemplates: (outDir: string, options: Options) => Promise<never>;
|
|
2
|
+
export declare const exportTemplates: (outDir: string, srcDir: string, options: Options) => Promise<never>;
|
|
@@ -37,14 +37,15 @@ const fs_1 = require("fs");
|
|
|
37
37
|
const cpy_1 = __importDefault(require("cpy"));
|
|
38
38
|
const normalize_path_1 = __importDefault(require("normalize-path"));
|
|
39
39
|
const utils_1 = require("../utils");
|
|
40
|
+
const path_1 = __importDefault(require("path"));
|
|
40
41
|
/*
|
|
41
42
|
This first builds all the templates using esbuild and then puts the output in the `.js`
|
|
42
43
|
files. Then these `.js` files are imported dynamically and rendered to `.html` files
|
|
43
44
|
using the `render` function.
|
|
44
45
|
*/
|
|
45
|
-
const exportTemplates = async (outDir, options) => {
|
|
46
|
+
const exportTemplates = async (outDir, srcDir, options) => {
|
|
46
47
|
const spinner = (0, ora_1.default)('Preparing files...\n').start();
|
|
47
|
-
const allTemplates = glob_1.glob.sync((0, normalize_path_1.default)(
|
|
48
|
+
const allTemplates = glob_1.glob.sync((0, normalize_path_1.default)(path_1.default.join(srcDir, '*.{tsx,jsx}')));
|
|
48
49
|
esbuild_1.default.buildSync({
|
|
49
50
|
bundle: true,
|
|
50
51
|
entryPoints: allTemplates,
|
|
@@ -62,9 +63,10 @@ const exportTemplates = async (outDir, options) => {
|
|
|
62
63
|
(0, fs_1.writeFileSync)(htmlPath, rendered);
|
|
63
64
|
(0, fs_1.unlinkSync)(template);
|
|
64
65
|
}
|
|
65
|
-
const
|
|
66
|
+
const staticDir = path_1.default.join(srcDir, 'static');
|
|
67
|
+
const hasStaticDirectory = (0, utils_1.checkDirectoryExist)(staticDir);
|
|
66
68
|
if (hasStaticDirectory) {
|
|
67
|
-
await (0, cpy_1.default)(
|
|
69
|
+
await (0, cpy_1.default)(staticDir, `${outDir}/static`);
|
|
68
70
|
}
|
|
69
71
|
const fileTree = (0, tree_node_cli_1.default)(outDir, {
|
|
70
72
|
allFiles: true,
|
package/dist/source/index.js
CHANGED
|
@@ -5,9 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const extra_typings_1 = require("@commander-js/extra-typings");
|
|
8
|
-
const constants_1 = require("./utils/constants");
|
|
9
8
|
const dev_1 = require("./commands/dev");
|
|
10
9
|
const export_1 = require("./commands/export");
|
|
10
|
+
const constants_1 = require("./utils/constants");
|
|
11
11
|
const package_json_1 = __importDefault(require("../package.json"));
|
|
12
12
|
extra_typings_1.program
|
|
13
13
|
.name(constants_1.PACKAGE_NAME)
|
|
@@ -16,12 +16,14 @@ extra_typings_1.program
|
|
|
16
16
|
extra_typings_1.program
|
|
17
17
|
.command('dev')
|
|
18
18
|
.description('Starts the application in development mode')
|
|
19
|
-
.
|
|
19
|
+
.option('-d, --dir <path>', 'Directory with your email templates', './emails')
|
|
20
|
+
.action((args) => (0, dev_1.dev)(args));
|
|
20
21
|
extra_typings_1.program
|
|
21
22
|
.command('export')
|
|
22
23
|
.description('Build the templates to the `out` directory')
|
|
23
24
|
.option('--outDir <path>', 'Output directory', 'out')
|
|
24
25
|
.option('-p, --pretty', 'Pretty print the output', false)
|
|
25
|
-
.option('-t, --plainText', 'Set output format as plain
|
|
26
|
-
.
|
|
26
|
+
.option('-t, --plainText', 'Set output format as plain text', false)
|
|
27
|
+
.option('-d, --dir <path>', 'Directory with your email templates', './emails')
|
|
28
|
+
.action(({ outDir, pretty, plainText, dir: srcDir }) => (0, export_1.exportTemplates)(outDir, srcDir, { pretty, plainText }));
|
|
27
29
|
extra_typings_1.program.parse();
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import chokidar from 'chokidar';
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const watcher: () =>
|
|
1
|
+
import chokidar, { FSWatcher } from 'chokidar';
|
|
2
|
+
export declare const createWatcherInstance: (watchDir: string) => chokidar.FSWatcher;
|
|
3
|
+
export declare const watcher: (watcherInstance: FSWatcher, watchDir: string) => void;
|
|
@@ -3,33 +3,38 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.watcher = exports.
|
|
6
|
+
exports.watcher = exports.createWatcherInstance = void 0;
|
|
7
7
|
const chokidar_1 = __importDefault(require("chokidar"));
|
|
8
8
|
const constants_1 = require("./constants");
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const cpy_1 = __importDefault(require("cpy"));
|
|
12
|
-
|
|
12
|
+
const createWatcherInstance = (watchDir) => chokidar_1.default.watch(watchDir, {
|
|
13
13
|
ignoreInitial: true,
|
|
14
14
|
cwd: constants_1.CURRENT_PATH,
|
|
15
15
|
ignored: /(^|[\/\\])\../,
|
|
16
16
|
});
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
exports.createWatcherInstance = createWatcherInstance;
|
|
18
|
+
const watcher = (watcherInstance, watchDir) => {
|
|
19
|
+
watcherInstance.on('all', async (event, filename) => {
|
|
19
20
|
const file = filename.split(path_1.default.sep);
|
|
20
|
-
if (file[1] ===
|
|
21
|
-
|
|
21
|
+
if (file[1] === undefined) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (event === constants_1.EVENT_FILE_DELETED) {
|
|
25
|
+
if (file[1] === 'static' && file[2]) {
|
|
26
|
+
await fs_1.default.promises.rm(path_1.default.join(constants_1.REACT_EMAIL_ROOT, 'public', 'static', file[2]));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
await fs_1.default.promises.rm(path_1.default.join(constants_1.REACT_EMAIL_ROOT, filename));
|
|
22
30
|
return;
|
|
23
31
|
}
|
|
24
|
-
await fs_1.default.promises.rm(path_1.default.join(constants_1.REACT_EMAIL_ROOT, filename));
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
const file = filename.split(path_1.default.sep);
|
|
28
32
|
if (file[1] === 'static' && file[2]) {
|
|
29
|
-
|
|
33
|
+
const srcPath = path_1.default.join(watchDir, 'static', file[2]);
|
|
34
|
+
await (0, cpy_1.default)(srcPath, `${constants_1.REACT_EMAIL_ROOT}/public/static`);
|
|
30
35
|
return;
|
|
31
36
|
}
|
|
32
|
-
await (0, cpy_1.default)(path_1.default.join(
|
|
33
|
-
}
|
|
34
|
-
}
|
|
37
|
+
await (0, cpy_1.default)(path_1.default.join(watchDir, ...file.slice(1)), path_1.default.join(constants_1.PACKAGE_EMAILS_PATH, ...file.slice(1, -1)));
|
|
38
|
+
});
|
|
39
|
+
};
|
|
35
40
|
exports.watcher = watcher;
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Html } from '@react-email/html';
|
|
3
|
+
import { Button } from '@react-email/button';
|
|
4
|
+
import { Text } from '@react-email/text';
|
|
5
|
+
import { Hr } from '@react-email/hr';
|
|
6
|
+
|
|
7
|
+
export default function Email() {
|
|
8
|
+
return (
|
|
9
|
+
<Html lang="en">
|
|
10
|
+
<Text>Lorem ipsum</Text>
|
|
11
|
+
<Hr />
|
|
12
|
+
<Button href="https://example.com">Click me</Button>
|
|
13
|
+
</Html>
|
|
14
|
+
);
|
|
15
|
+
};
|
package/preview/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-email-preview",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "The React Email preview application",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"scripts": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"format": "prettier --write \"**/*.{ts,tsx,md}\""
|
|
13
13
|
},
|
|
14
14
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
15
|
+
"node": ">=16.0.0"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@next/font": "13.0.4",
|
package/source/_preview/root.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const root = [
|
|
|
12
12
|
{
|
|
13
13
|
title: 'package.json',
|
|
14
14
|
content:
|
|
15
|
-
'{\n "name": "react-email-preview",\n "version": "0.0.
|
|
15
|
+
'{\n "name": "react-email-preview",\n "version": "0.0.10",\n "description": "The React Email preview application",\n "license": "MIT",\n "scripts": {\n "dev": "next dev",\n "build": "next build",\n "start": "next start",\n "lint": "next lint",\n "format:check": "prettier --check \\"**/*.{ts,tsx,md}\\"",\n "format": "prettier --write \\"**/*.{ts,tsx,md}\\""\n },\n "engines": {\n "node": ">=16.0.0"\n },\n "dependencies": {\n "@next/font": "13.0.4",\n "@radix-ui/colors": "0.1.8",\n "@radix-ui/react-collapsible": "1.0.1",\n "@radix-ui/react-popover": "1.0.2",\n "@radix-ui/react-slot": "1.0.1",\n "@radix-ui/react-toggle-group": "1.0.1",\n "@radix-ui/react-tooltip": "1.0.2",\n "@react-email/render": "0.0.6",\n "classnames": "2.3.2",\n "framer-motion": "8.4.6",\n "next": "13.0.4",\n "prism-react-renderer": "1.3.5",\n "react": "18.2.0",\n "react-dom": "18.2.0"\n },\n "devDependencies": {\n "@types/classnames": "2.3.1",\n "@types/node": "18.11.9",\n "@types/react": "18.0.25",\n "@types/react-dom": "18.0.9",\n "autoprefixer": "10.4.13",\n "postcss": "8.4.19",\n "tailwindcss": "3.2.4",\n "typescript": "4.9.3"\n }\n}\n',
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
title: 'postcss.config.js',
|
package/source/commands/dev.ts
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
checkDirectoryExist,
|
|
3
3
|
checkEmptyDirectory,
|
|
4
4
|
checkPackageIsUpToDate,
|
|
5
|
-
CLIENT_EMAILS_PATH,
|
|
6
5
|
createDirectory,
|
|
6
|
+
createWatcherInstance,
|
|
7
7
|
CURRENT_PATH,
|
|
8
8
|
PACKAGE_EMAILS_PATH,
|
|
9
9
|
REACT_EMAIL_ROOT,
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
getPreviewPkg,
|
|
12
12
|
watcher,
|
|
13
13
|
PUBLIC_PATH,
|
|
14
|
-
watcherInstance,
|
|
15
14
|
} from '../utils';
|
|
16
15
|
import path from 'path';
|
|
17
16
|
import fs from 'fs';
|
|
@@ -27,7 +26,13 @@ import readPackage from 'read-pkg';
|
|
|
27
26
|
import shell from 'shelljs';
|
|
28
27
|
import { styles } from '../_preview/styles';
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
interface Args {
|
|
30
|
+
dir: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const dev = async ({ dir }: Args) => {
|
|
34
|
+
const emailDir = convertToAbsolutePath(dir);
|
|
35
|
+
const watcherInstance = createWatcherInstance(emailDir);
|
|
31
36
|
try {
|
|
32
37
|
const hasReactEmailDirectory = checkDirectoryExist(REACT_EMAIL_ROOT);
|
|
33
38
|
let packageManager: PackageManager;
|
|
@@ -41,10 +46,10 @@ export const dev = async () => {
|
|
|
41
46
|
const isUpToDate = await checkPackageIsUpToDate();
|
|
42
47
|
|
|
43
48
|
if (isUpToDate) {
|
|
44
|
-
await Promise.all([generateEmailsPreview(), syncPkg()]);
|
|
49
|
+
await Promise.all([generateEmailsPreview(emailDir), syncPkg()]);
|
|
45
50
|
await installDependencies(packageManager);
|
|
46
51
|
shell.exec(`${packageManager} run dev`, { async: true });
|
|
47
|
-
watcher();
|
|
52
|
+
watcher(watcherInstance, emailDir);
|
|
48
53
|
return;
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -54,16 +59,19 @@ export const dev = async () => {
|
|
|
54
59
|
await createBasicStructure();
|
|
55
60
|
await createAppDirectories();
|
|
56
61
|
await createAppFiles();
|
|
57
|
-
await Promise.all([generateEmailsPreview(), syncPkg()]);
|
|
62
|
+
await Promise.all([generateEmailsPreview(emailDir), syncPkg()]);
|
|
58
63
|
await installDependencies(packageManager);
|
|
59
64
|
shell.exec(`${packageManager} run dev`, { async: true });
|
|
60
|
-
watcher();
|
|
65
|
+
watcher(watcherInstance, emailDir);
|
|
61
66
|
} catch (error) {
|
|
62
67
|
await watcherInstance.close();
|
|
63
68
|
shell.exit(1);
|
|
64
69
|
}
|
|
65
70
|
};
|
|
66
71
|
|
|
72
|
+
const convertToAbsolutePath = (dir: string): string =>
|
|
73
|
+
path.isAbsolute(dir) ? dir : path.join(process.cwd(), dir);
|
|
74
|
+
|
|
67
75
|
const createBasicStructure = async () => {
|
|
68
76
|
try {
|
|
69
77
|
// Create `.react-email` directory
|
|
@@ -129,13 +137,13 @@ const createAppFiles = async () => {
|
|
|
129
137
|
}
|
|
130
138
|
};
|
|
131
139
|
|
|
132
|
-
const generateEmailsPreview = async () => {
|
|
140
|
+
const generateEmailsPreview = async (emailDir: string) => {
|
|
133
141
|
try {
|
|
134
142
|
const spinner = ora('Generating emails preview').start();
|
|
135
143
|
|
|
136
|
-
await createEmailPreviews();
|
|
137
|
-
await
|
|
138
|
-
await createComponents();
|
|
144
|
+
await createEmailPreviews(emailDir);
|
|
145
|
+
await createStaticFiles(emailDir);
|
|
146
|
+
await createComponents(emailDir);
|
|
139
147
|
|
|
140
148
|
spinner.stopAndPersist({
|
|
141
149
|
symbol: logSymbols.success,
|
|
@@ -146,11 +154,11 @@ const generateEmailsPreview = async () => {
|
|
|
146
154
|
}
|
|
147
155
|
};
|
|
148
156
|
|
|
149
|
-
const createEmailPreviews = async () => {
|
|
150
|
-
const hasEmailsDirectory = checkDirectoryExist(
|
|
157
|
+
const createEmailPreviews = async (emailDir: string) => {
|
|
158
|
+
const hasEmailsDirectory = checkDirectoryExist(emailDir);
|
|
151
159
|
|
|
152
160
|
const isEmailsDirectoryEmpty = hasEmailsDirectory
|
|
153
|
-
? await checkEmptyDirectory(
|
|
161
|
+
? await checkEmptyDirectory(emailDir)
|
|
154
162
|
: true;
|
|
155
163
|
|
|
156
164
|
if (isEmailsDirectoryEmpty) {
|
|
@@ -162,15 +170,16 @@ const createEmailPreviews = async () => {
|
|
|
162
170
|
await fs.promises.rm(PACKAGE_EMAILS_PATH, { recursive: true });
|
|
163
171
|
}
|
|
164
172
|
|
|
165
|
-
await copy(
|
|
173
|
+
await copy(path.join(emailDir, '*{.tsx,.jsx}'), PACKAGE_EMAILS_PATH);
|
|
166
174
|
};
|
|
167
175
|
|
|
168
|
-
const
|
|
176
|
+
const createStaticFiles = async (emailDir: string) => {
|
|
169
177
|
const hasPackageStaticDirectory = checkDirectoryExist(
|
|
170
178
|
`${REACT_EMAIL_ROOT}/public/static`,
|
|
171
179
|
);
|
|
180
|
+
const staticDir = path.join(emailDir, 'static')
|
|
172
181
|
const hasStaticDirectory = checkDirectoryExist(
|
|
173
|
-
|
|
182
|
+
staticDir,
|
|
174
183
|
);
|
|
175
184
|
|
|
176
185
|
if (hasPackageStaticDirectory) {
|
|
@@ -181,19 +190,19 @@ const createStatisFiles = async () => {
|
|
|
181
190
|
|
|
182
191
|
if (hasStaticDirectory) {
|
|
183
192
|
await copy(
|
|
184
|
-
|
|
193
|
+
staticDir,
|
|
185
194
|
`${REACT_EMAIL_ROOT}/public/static`,
|
|
186
195
|
);
|
|
187
196
|
}
|
|
188
197
|
};
|
|
189
198
|
|
|
190
|
-
const createComponents = async () => {
|
|
199
|
+
const createComponents = async (emailDir: string) => {
|
|
191
200
|
const hasPackageComponentsDirectory = checkDirectoryExist(
|
|
192
201
|
`${PACKAGE_EMAILS_PATH}/components`,
|
|
193
202
|
);
|
|
194
|
-
|
|
203
|
+
const componentDir = path.join(emailDir, 'components')
|
|
195
204
|
const hasComponentsDirectory = checkDirectoryExist(
|
|
196
|
-
|
|
205
|
+
componentDir,
|
|
197
206
|
);
|
|
198
207
|
|
|
199
208
|
if (hasPackageComponentsDirectory) {
|
|
@@ -204,7 +213,7 @@ const createComponents = async () => {
|
|
|
204
213
|
|
|
205
214
|
if (hasComponentsDirectory) {
|
|
206
215
|
await copy(
|
|
207
|
-
|
|
216
|
+
componentDir,
|
|
208
217
|
`${PACKAGE_EMAILS_PATH}/components`,
|
|
209
218
|
);
|
|
210
219
|
}
|
|
@@ -7,17 +7,17 @@ import { render, Options } from '@react-email/render';
|
|
|
7
7
|
import { unlinkSync, writeFileSync } from 'fs';
|
|
8
8
|
import copy from 'cpy';
|
|
9
9
|
import normalize from 'normalize-path';
|
|
10
|
-
import { checkDirectoryExist
|
|
11
|
-
|
|
10
|
+
import { checkDirectoryExist } from '../utils';
|
|
11
|
+
import path from 'path';
|
|
12
12
|
/*
|
|
13
13
|
This first builds all the templates using esbuild and then puts the output in the `.js`
|
|
14
14
|
files. Then these `.js` files are imported dynamically and rendered to `.html` files
|
|
15
15
|
using the `render` function.
|
|
16
16
|
*/
|
|
17
|
-
export const exportTemplates = async (outDir: string, options: Options) => {
|
|
17
|
+
export const exportTemplates = async (outDir: string, srcDir: string, options: Options) => {
|
|
18
18
|
const spinner = ora('Preparing files...\n').start();
|
|
19
19
|
const allTemplates = glob.sync(
|
|
20
|
-
normalize(
|
|
20
|
+
normalize(path.join(srcDir, '*.{tsx,jsx}')),
|
|
21
21
|
);
|
|
22
22
|
|
|
23
23
|
esbuild.buildSync({
|
|
@@ -43,12 +43,13 @@ export const exportTemplates = async (outDir: string, options: Options) => {
|
|
|
43
43
|
unlinkSync(template);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const staticDir = path.join(srcDir, 'static')
|
|
46
47
|
const hasStaticDirectory = checkDirectoryExist(
|
|
47
|
-
|
|
48
|
+
staticDir
|
|
48
49
|
);
|
|
49
50
|
|
|
50
51
|
if (hasStaticDirectory) {
|
|
51
|
-
await copy(
|
|
52
|
+
await copy(staticDir, `${outDir}/static`);
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
const fileTree = tree(outDir, {
|
package/source/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program } from '@commander-js/extra-typings';
|
|
3
|
-
import { PACKAGE_NAME } from './utils/constants';
|
|
4
3
|
import { dev } from './commands/dev';
|
|
5
4
|
import { exportTemplates } from './commands/export';
|
|
5
|
+
import { PACKAGE_NAME } from './utils/constants';
|
|
6
6
|
import packageJson from '../package.json';
|
|
7
7
|
|
|
8
8
|
program
|
|
@@ -13,16 +13,18 @@ program
|
|
|
13
13
|
program
|
|
14
14
|
.command('dev')
|
|
15
15
|
.description('Starts the application in development mode')
|
|
16
|
-
.
|
|
16
|
+
.option('-d, --dir <path>', 'Directory with your email templates', './emails')
|
|
17
|
+
.action((args) => dev(args));
|
|
17
18
|
|
|
18
19
|
program
|
|
19
20
|
.command('export')
|
|
20
21
|
.description('Build the templates to the `out` directory')
|
|
21
22
|
.option('--outDir <path>', 'Output directory', 'out')
|
|
22
23
|
.option('-p, --pretty', 'Pretty print the output', false)
|
|
23
|
-
.option('-t, --plainText', 'Set output format as plain
|
|
24
|
-
.
|
|
25
|
-
|
|
24
|
+
.option('-t, --plainText', 'Set output format as plain text', false)
|
|
25
|
+
.option('-d, --dir <path>', 'Directory with your email templates', './emails')
|
|
26
|
+
.action(({ outDir, pretty, plainText, dir: srcDir }) =>
|
|
27
|
+
exportTemplates(outDir, srcDir, { pretty, plainText }),
|
|
26
28
|
);
|
|
27
29
|
|
|
28
30
|
program.parse();
|
package/source/utils/watcher.ts
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
import chokidar from 'chokidar';
|
|
1
|
+
import chokidar, { FSWatcher } from 'chokidar';
|
|
2
2
|
import {
|
|
3
|
-
CLIENT_EMAILS_PATH,
|
|
4
3
|
CURRENT_PATH,
|
|
5
4
|
EVENT_FILE_DELETED,
|
|
5
|
+
PACKAGE_EMAILS_PATH,
|
|
6
6
|
REACT_EMAIL_ROOT,
|
|
7
7
|
} from './constants';
|
|
8
8
|
import fs from 'fs';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import copy from 'cpy';
|
|
11
11
|
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
export const createWatcherInstance = (watchDir: string) =>
|
|
13
|
+
chokidar.watch(watchDir, {
|
|
14
|
+
ignoreInitial: true,
|
|
15
|
+
cwd: CURRENT_PATH,
|
|
16
|
+
ignored: /(^|[\/\\])\../,
|
|
17
|
+
});
|
|
17
18
|
|
|
18
|
-
export const watcher = () =>
|
|
19
|
+
export const watcher = (watcherInstance: FSWatcher, watchDir: string) => {
|
|
19
20
|
watcherInstance.on('all', async (event, filename) => {
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
const file = filename.split(path.sep);
|
|
22
|
+
if (file[1] === undefined) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
22
25
|
|
|
26
|
+
if (event === EVENT_FILE_DELETED) {
|
|
23
27
|
if (file[1] === 'static' && file[2]) {
|
|
24
28
|
await fs.promises.rm(
|
|
25
29
|
path.join(REACT_EMAIL_ROOT, 'public', 'static', file[2]),
|
|
@@ -28,20 +32,17 @@ export const watcher = () =>
|
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
await fs.promises.rm(path.join(REACT_EMAIL_ROOT, filename));
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (file[1] === 'static' && file[2]) {
|
|
35
|
-
await copy(
|
|
36
|
-
`${CLIENT_EMAILS_PATH}/static/${file[2]}`,
|
|
37
|
-
`${REACT_EMAIL_ROOT}/public/static`,
|
|
38
|
-
);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
if (file[1] === 'static' && file[2]) {
|
|
39
|
+
const srcPath = path.join(watchDir, 'static', file[2]);
|
|
40
|
+
await copy(srcPath, `${REACT_EMAIL_ROOT}/public/static`);
|
|
41
|
+
return;
|
|
46
42
|
}
|
|
43
|
+
await copy(
|
|
44
|
+
path.join(watchDir, ...file.slice(1)),
|
|
45
|
+
path.join(PACKAGE_EMAILS_PATH, ...file.slice(1, -1)),
|
|
46
|
+
);
|
|
47
47
|
});
|
|
48
|
+
};
|