react-email 1.9.3 → 1.9.4
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/commands/export.js +7 -0
- package/dist/source/index.js +0 -0
- package/dist/source/utils/generate-email-preview.js +11 -4
- package/dist/source/utils/start-server-command.js +10 -7
- package/dist/source/utils/watcher.js +14 -5
- package/package.json +1 -1
- package/source/commands/export.ts +8 -1
- package/source/utils/close-ora-on-sigint.ts +3 -3
- package/source/utils/generate-email-preview.ts +13 -5
- package/source/utils/install-dependencies.ts +1 -1
- package/source/utils/start-server-command.ts +19 -14
- package/source/utils/watcher.ts +12 -2
package/dist/package.json
CHANGED
|
@@ -55,16 +55,22 @@ const exportTemplates = async (outDir, srcDir, options) => {
|
|
|
55
55
|
write: true,
|
|
56
56
|
outdir: outDir,
|
|
57
57
|
});
|
|
58
|
+
spinner.succeed();
|
|
58
59
|
const allBuiltTemplates = glob_1.glob.sync((0, normalize_path_1.default)(`${outDir}/*.js`), {
|
|
59
60
|
absolute: true,
|
|
60
61
|
});
|
|
61
62
|
for (const template of allBuiltTemplates) {
|
|
63
|
+
spinner.text = `rendering ${template.split('/').pop()}`;
|
|
64
|
+
spinner.render();
|
|
62
65
|
const component = await Promise.resolve(`${template}`).then(s => __importStar(require(s)));
|
|
63
66
|
const rendered = (0, render_1.render)(component.default({}), options);
|
|
64
67
|
const htmlPath = template.replace('.js', options.plainText ? '.txt' : '.html');
|
|
65
68
|
(0, fs_1.writeFileSync)(htmlPath, rendered);
|
|
66
69
|
(0, fs_1.unlinkSync)(template);
|
|
67
70
|
}
|
|
71
|
+
spinner.succeed('Rendered all files');
|
|
72
|
+
spinner.text = `Copying static files`;
|
|
73
|
+
spinner.render();
|
|
68
74
|
const staticDir = path_1.default.join(srcDir, 'static');
|
|
69
75
|
const hasStaticDirectory = fs_2.default.existsSync(staticDir);
|
|
70
76
|
if (hasStaticDirectory) {
|
|
@@ -73,6 +79,7 @@ const exportTemplates = async (outDir, srcDir, options) => {
|
|
|
73
79
|
throw new Error(`Something went wrong while copying the file to ${outDir}/static, ${result.cat()}`);
|
|
74
80
|
}
|
|
75
81
|
}
|
|
82
|
+
spinner.succeed();
|
|
76
83
|
const fileTree = (0, tree_node_cli_1.default)(outDir, {
|
|
77
84
|
allFiles: true,
|
|
78
85
|
maxDepth: 4,
|
package/dist/source/index.js
CHANGED
|
File without changes
|
|
@@ -13,6 +13,12 @@ const path_1 = __importDefault(require("path"));
|
|
|
13
13
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
14
14
|
const glob_1 = __importDefault(require("glob"));
|
|
15
15
|
const close_ora_on_sigint_1 = require("./close-ora-on-sigint");
|
|
16
|
+
/**
|
|
17
|
+
* Node.js and imports are requiring all imports to be /, while some functions (like glob) return paths with \ for path separation on windows
|
|
18
|
+
*/
|
|
19
|
+
function osIndependentPath(p) {
|
|
20
|
+
return p.split(path_1.default.sep).join("/");
|
|
21
|
+
}
|
|
16
22
|
const generateEmailsPreview = async (emailDir, type = 'all') => {
|
|
17
23
|
try {
|
|
18
24
|
const spinner = (0, ora_1.default)('Generating emails preview').start();
|
|
@@ -38,7 +44,7 @@ const createEmailPreviews = async (emailDir) => {
|
|
|
38
44
|
if (hasEmailsDirectory) {
|
|
39
45
|
await fs_1.default.promises.rm(constants_1.PACKAGE_EMAILS_PATH, { recursive: true });
|
|
40
46
|
}
|
|
41
|
-
const list = glob_1.default.sync(path_1.default.join(emailDir, '/*.{jsx,tsx}'), {
|
|
47
|
+
const list = glob_1.default.sync(osIndependentPath(path_1.default.join(emailDir, '/*.{jsx,tsx}')), {
|
|
42
48
|
absolute: true,
|
|
43
49
|
});
|
|
44
50
|
/**
|
|
@@ -48,11 +54,12 @@ const createEmailPreviews = async (emailDir) => {
|
|
|
48
54
|
* import Mail from '../../path/to/emails/my-template.tsx`
|
|
49
55
|
* export default Mail
|
|
50
56
|
*/
|
|
51
|
-
for (const
|
|
57
|
+
for (const _absoluteSrcFilePath of list) {
|
|
58
|
+
const absoluteSrcFilePath = osIndependentPath(_absoluteSrcFilePath);
|
|
52
59
|
const fileName = absoluteSrcFilePath.split('/').pop();
|
|
53
|
-
const targetFile = path_1.default.join(constants_1.PACKAGE_EMAILS_PATH, absoluteSrcFilePath.replace(emailDir, ''));
|
|
60
|
+
const targetFile = path_1.default.join(osIndependentPath(constants_1.PACKAGE_EMAILS_PATH), absoluteSrcFilePath.replace(osIndependentPath(emailDir), ''));
|
|
54
61
|
const importPath = path_1.default.relative(path_1.default.dirname(targetFile), path_1.default.dirname(absoluteSrcFilePath));
|
|
55
|
-
const importFile = path_1.default.join(importPath, fileName);
|
|
62
|
+
const importFile = osIndependentPath(path_1.default.join(importPath, fileName));
|
|
56
63
|
// if this import is changed, you also need to update `client/src/app/preview/[slug]/page.tsx`
|
|
57
64
|
const sourceCode = `import Mail from '${importFile}';export default Mail;`.replace(';', ';\n');
|
|
58
65
|
await fs_extra_1.default.ensureDir(path_1.default.dirname(targetFile));
|
|
@@ -30,7 +30,7 @@ const buildProdServer = (packageManager) => {
|
|
|
30
30
|
};
|
|
31
31
|
exports.buildProdServer = buildProdServer;
|
|
32
32
|
// based on https://stackoverflow.com/a/14032965
|
|
33
|
-
|
|
33
|
+
const exitHandler = (options) => (code) => {
|
|
34
34
|
if (processesToKill.length > 0) {
|
|
35
35
|
console.log('shutting down %d subprocesses', processesToKill.length);
|
|
36
36
|
}
|
|
@@ -39,13 +39,16 @@ function exitHandler() {
|
|
|
39
39
|
p.kill();
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
|
-
|
|
42
|
+
if (options?.exit) {
|
|
43
|
+
shelljs_1.default.exit(code);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
43
46
|
// do something when app is closing
|
|
44
|
-
process.on('exit', exitHandler);
|
|
47
|
+
process.on('exit', exitHandler());
|
|
45
48
|
// catches ctrl+c event
|
|
46
|
-
process.on('SIGINT', exitHandler);
|
|
49
|
+
process.on('SIGINT', exitHandler({ exit: true }));
|
|
47
50
|
// catches "kill pid" (for example: nodemon restart)
|
|
48
|
-
process.on('SIGUSR1', exitHandler);
|
|
49
|
-
process.on('SIGUSR2', exitHandler);
|
|
51
|
+
process.on('SIGUSR1', exitHandler({ exit: true }));
|
|
52
|
+
process.on('SIGUSR2', exitHandler({ exit: true }));
|
|
50
53
|
// catches uncaught exceptions
|
|
51
|
-
process.on('uncaughtException', exitHandler);
|
|
54
|
+
process.on('uncaughtException', exitHandler({ exit: true }));
|
|
@@ -10,11 +10,20 @@ const path_1 = __importDefault(require("path"));
|
|
|
10
10
|
const shelljs_1 = __importDefault(require("shelljs"));
|
|
11
11
|
const constants_1 = require("./constants");
|
|
12
12
|
const generate_email_preview_1 = require("./generate-email-preview");
|
|
13
|
-
const createWatcherInstance = (watchDir) =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const createWatcherInstance = (watchDir) => {
|
|
14
|
+
const watcher = chokidar_1.default.watch(watchDir, {
|
|
15
|
+
ignoreInitial: true,
|
|
16
|
+
cwd: watchDir.split(path_1.default.sep).slice(0, -1).join(path_1.default.sep),
|
|
17
|
+
ignored: /(^|[\/\\])\../,
|
|
18
|
+
});
|
|
19
|
+
// Catches ctrl+c event
|
|
20
|
+
const exit = async () => {
|
|
21
|
+
await watcher.close();
|
|
22
|
+
};
|
|
23
|
+
process.on('SIGINT', exit);
|
|
24
|
+
process.on('uncaughtException', exit);
|
|
25
|
+
return watcher;
|
|
26
|
+
};
|
|
18
27
|
exports.createWatcherInstance = createWatcherInstance;
|
|
19
28
|
const watcher = (watcherInstance, watchDir) => {
|
|
20
29
|
watcherInstance.on('all', async (event, filename) => {
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@ export const exportTemplates = async (
|
|
|
21
21
|
options: Options,
|
|
22
22
|
) => {
|
|
23
23
|
const spinner = ora('Preparing files...\n').start();
|
|
24
|
-
closeOraOnSIGNIT(spinner)
|
|
24
|
+
closeOraOnSIGNIT(spinner);
|
|
25
25
|
|
|
26
26
|
const allTemplates = glob.sync(normalize(path.join(srcDir, '*.{tsx,jsx}')));
|
|
27
27
|
|
|
@@ -32,12 +32,15 @@ export const exportTemplates = async (
|
|
|
32
32
|
write: true,
|
|
33
33
|
outdir: outDir,
|
|
34
34
|
});
|
|
35
|
+
spinner.succeed();
|
|
35
36
|
|
|
36
37
|
const allBuiltTemplates = glob.sync(normalize(`${outDir}/*.js`), {
|
|
37
38
|
absolute: true,
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
for (const template of allBuiltTemplates) {
|
|
42
|
+
spinner.text = `rendering ${template.split('/').pop()}`;
|
|
43
|
+
spinner.render();
|
|
41
44
|
const component = await import(template);
|
|
42
45
|
const rendered = render(component.default({}), options);
|
|
43
46
|
const htmlPath = template.replace(
|
|
@@ -47,6 +50,9 @@ export const exportTemplates = async (
|
|
|
47
50
|
writeFileSync(htmlPath, rendered);
|
|
48
51
|
unlinkSync(template);
|
|
49
52
|
}
|
|
53
|
+
spinner.succeed('Rendered all files');
|
|
54
|
+
spinner.text = `Copying static files`;
|
|
55
|
+
spinner.render();
|
|
50
56
|
|
|
51
57
|
const staticDir = path.join(srcDir, 'static');
|
|
52
58
|
const hasStaticDirectory = fs.existsSync(staticDir);
|
|
@@ -59,6 +65,7 @@ export const exportTemplates = async (
|
|
|
59
65
|
);
|
|
60
66
|
}
|
|
61
67
|
}
|
|
68
|
+
spinner.succeed();
|
|
62
69
|
|
|
63
70
|
const fileTree = tree(outDir, {
|
|
64
71
|
allFiles: true,
|
|
@@ -12,6 +12,13 @@ import fse from 'fs-extra';
|
|
|
12
12
|
import glob from 'glob';
|
|
13
13
|
import { closeOraOnSIGNIT } from './close-ora-on-sigint';
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Node.js and imports are requiring all imports to be /, while some functions (like glob) return paths with \ for path separation on windows
|
|
17
|
+
*/
|
|
18
|
+
function osIndependentPath(p: string) {
|
|
19
|
+
return p.split(path.sep).join("/")
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
export const generateEmailsPreview = async (
|
|
16
23
|
emailDir: string,
|
|
17
24
|
type: 'all' | 'static' | 'templates' = 'all',
|
|
@@ -43,7 +50,7 @@ const createEmailPreviews = async (emailDir: string) => {
|
|
|
43
50
|
await fs.promises.rm(PACKAGE_EMAILS_PATH, { recursive: true });
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
const list = glob.sync(path.join(emailDir, '/*.{jsx,tsx}'), {
|
|
53
|
+
const list = glob.sync(osIndependentPath(path.join(emailDir, '/*.{jsx,tsx}')), {
|
|
47
54
|
absolute: true,
|
|
48
55
|
});
|
|
49
56
|
|
|
@@ -54,18 +61,19 @@ const createEmailPreviews = async (emailDir: string) => {
|
|
|
54
61
|
* import Mail from '../../path/to/emails/my-template.tsx`
|
|
55
62
|
* export default Mail
|
|
56
63
|
*/
|
|
57
|
-
for (const
|
|
64
|
+
for (const _absoluteSrcFilePath of list) {
|
|
65
|
+
const absoluteSrcFilePath = osIndependentPath(_absoluteSrcFilePath);
|
|
58
66
|
const fileName = absoluteSrcFilePath.split('/').pop()!;
|
|
59
67
|
const targetFile = path.join(
|
|
60
|
-
PACKAGE_EMAILS_PATH,
|
|
61
|
-
absoluteSrcFilePath.replace(emailDir, ''),
|
|
68
|
+
osIndependentPath(PACKAGE_EMAILS_PATH),
|
|
69
|
+
absoluteSrcFilePath.replace(osIndependentPath(emailDir), ''),
|
|
62
70
|
);
|
|
63
71
|
const importPath = path.relative(
|
|
64
72
|
path.dirname(targetFile),
|
|
65
73
|
path.dirname(absoluteSrcFilePath),
|
|
66
74
|
);
|
|
67
75
|
|
|
68
|
-
const importFile = path.join(importPath, fileName);
|
|
76
|
+
const importFile = osIndependentPath(path.join(importPath, fileName));
|
|
69
77
|
|
|
70
78
|
// if this import is changed, you also need to update `client/src/app/preview/[slug]/page.tsx`
|
|
71
79
|
const sourceCode =
|
|
@@ -9,7 +9,7 @@ export type PackageManager = 'yarn' | 'npm' | 'pnpm';
|
|
|
9
9
|
|
|
10
10
|
export const installDependencies = async (packageManager: PackageManager) => {
|
|
11
11
|
const spinner = ora('Installing dependencies...\n').start();
|
|
12
|
-
closeOraOnSIGNIT(spinner)
|
|
12
|
+
closeOraOnSIGNIT(spinner);
|
|
13
13
|
|
|
14
14
|
shell.cd(path.join(REACT_EMAIL_ROOT));
|
|
15
15
|
shell.exec(`${packageManager} install`);
|
|
@@ -29,26 +29,31 @@ export const buildProdServer = (packageManager: string) => {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
// based on https://stackoverflow.com/a/14032965
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (p.connected) {
|
|
38
|
-
p.kill();
|
|
32
|
+
const exitHandler: (options?: { exit?: boolean }) => NodeJS.ExitListener =
|
|
33
|
+
(options) =>
|
|
34
|
+
(code) => {
|
|
35
|
+
if (processesToKill.length > 0) {
|
|
36
|
+
console.log('shutting down %d subprocesses', processesToKill.length);
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
processesToKill.forEach((p) => {
|
|
39
|
+
if (p.connected) {
|
|
40
|
+
p.kill();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
if (options?.exit) {
|
|
44
|
+
shell.exit(code);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
42
47
|
|
|
43
48
|
// do something when app is closing
|
|
44
|
-
process.on('exit', exitHandler);
|
|
49
|
+
process.on('exit', exitHandler());
|
|
45
50
|
|
|
46
51
|
// catches ctrl+c event
|
|
47
|
-
process.on('SIGINT', exitHandler);
|
|
52
|
+
process.on('SIGINT', exitHandler({ exit: true }));
|
|
48
53
|
|
|
49
54
|
// catches "kill pid" (for example: nodemon restart)
|
|
50
|
-
process.on('SIGUSR1', exitHandler);
|
|
51
|
-
process.on('SIGUSR2', exitHandler);
|
|
55
|
+
process.on('SIGUSR1', exitHandler({ exit: true }));
|
|
56
|
+
process.on('SIGUSR2', exitHandler({ exit: true }));
|
|
52
57
|
|
|
53
58
|
// catches uncaught exceptions
|
|
54
|
-
process.on('uncaughtException', exitHandler);
|
|
59
|
+
process.on('uncaughtException', exitHandler({ exit: true }));
|
package/source/utils/watcher.ts
CHANGED
|
@@ -9,12 +9,22 @@ import {
|
|
|
9
9
|
} from './constants';
|
|
10
10
|
import { generateEmailsPreview } from './generate-email-preview';
|
|
11
11
|
|
|
12
|
-
export const createWatcherInstance = (watchDir: string) =>
|
|
13
|
-
chokidar.watch(watchDir, {
|
|
12
|
+
export const createWatcherInstance = (watchDir: string) => {
|
|
13
|
+
const watcher = chokidar.watch(watchDir, {
|
|
14
14
|
ignoreInitial: true,
|
|
15
15
|
cwd: watchDir.split(path.sep).slice(0, -1).join(path.sep),
|
|
16
16
|
ignored: /(^|[\/\\])\../,
|
|
17
17
|
});
|
|
18
|
+
|
|
19
|
+
// Catches ctrl+c event
|
|
20
|
+
const exit = async () => {
|
|
21
|
+
await watcher.close();
|
|
22
|
+
}
|
|
23
|
+
process.on('SIGINT', exit);
|
|
24
|
+
process.on('uncaughtException', exit);
|
|
25
|
+
|
|
26
|
+
return watcher;
|
|
27
|
+
}
|
|
18
28
|
|
|
19
29
|
export const watcher = (watcherInstance: FSWatcher, watchDir: string) => {
|
|
20
30
|
watcherInstance.on('all', async (event, filename) => {
|