react-email 1.9.1 → 1.9.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "A live preview of your emails right in your browser.",
5
5
  "bin": {
6
6
  "email": "./dist/source/index.js"
@@ -50,6 +50,7 @@
50
50
  "@types/normalize-path": "3.0.0",
51
51
  "@types/shelljs": "0.8.11",
52
52
  "prettier": "2.7.1",
53
- "ts-node": "10.9.1"
53
+ "ts-node": "10.9.1",
54
+ "typescript": "5.0.4"
54
55
  }
55
56
  }
@@ -38,14 +38,15 @@ const normalize_path_1 = __importDefault(require("normalize-path"));
38
38
  const path_1 = __importDefault(require("path"));
39
39
  const shelljs_1 = __importDefault(require("shelljs"));
40
40
  const fs_2 = __importDefault(require("fs"));
41
+ const close_ora_on_sigint_1 = require("../utils/close-ora-on-sigint");
41
42
  /*
42
43
  This first builds all the templates using esbuild and then puts the output in the `.js`
43
44
  files. Then these `.js` files are imported dynamically and rendered to `.html` files
44
45
  using the `render` function.
45
46
  */
46
47
  const exportTemplates = async (outDir, srcDir, options) => {
47
- var _a;
48
48
  const spinner = (0, ora_1.default)('Preparing files...\n').start();
49
+ (0, close_ora_on_sigint_1.closeOraOnSIGNIT)(spinner);
49
50
  const allTemplates = glob_1.glob.sync((0, normalize_path_1.default)(path_1.default.join(srcDir, '*.{tsx,jsx}')));
50
51
  esbuild_1.default.buildSync({
51
52
  bundle: true,
@@ -58,7 +59,7 @@ const exportTemplates = async (outDir, srcDir, options) => {
58
59
  absolute: true,
59
60
  });
60
61
  for (const template of allBuiltTemplates) {
61
- const component = await (_a = template, Promise.resolve().then(() => __importStar(require(_a))));
62
+ const component = await Promise.resolve(`${template}`).then(s => __importStar(require(s)));
62
63
  const rendered = (0, render_1.render)(component.default({}), options);
63
64
  const htmlPath = template.replace('.js', options.plainText ? '.txt' : '.html');
64
65
  (0, fs_1.writeFileSync)(htmlPath, rendered);
@@ -0,0 +1,2 @@
1
+ import { Ora } from 'ora';
2
+ export declare const closeOraOnSIGNIT: (spinner: Ora) => void;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.closeOraOnSIGNIT = void 0;
4
+ const closeOraOnSIGNIT = (spinner) => {
5
+ process.on('SIGINT', function () {
6
+ spinner.stop();
7
+ });
8
+ };
9
+ exports.closeOraOnSIGNIT = closeOraOnSIGNIT;
@@ -14,7 +14,7 @@ const downloadClient = async () => {
14
14
  const downloadRes = await octokit.repos.downloadTarballArchive({
15
15
  owner: 'resendlabs',
16
16
  repo: 'react-email',
17
- ref: 'v0.0.12',
17
+ ref: 'v0.0.13',
18
18
  });
19
19
  fs_1.default.mkdirSync('.react-email-temp');
20
20
  const TAR_PATH = path_1.default.join('.react-email-temp', 'react-email.tar.gz');
@@ -1 +1 @@
1
- export declare const generateEmailsPreview: (emailDir: string) => Promise<void>;
1
+ export declare const generateEmailsPreview: (emailDir: string, type?: 'all' | 'static' | 'templates') => Promise<void>;
@@ -11,11 +11,18 @@ const ora_1 = __importDefault(require("ora"));
11
11
  const shelljs_1 = __importDefault(require("shelljs"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const fs_extra_1 = __importDefault(require("fs-extra"));
14
- const generateEmailsPreview = async (emailDir) => {
14
+ const glob_1 = __importDefault(require("glob"));
15
+ const close_ora_on_sigint_1 = require("./close-ora-on-sigint");
16
+ const generateEmailsPreview = async (emailDir, type = 'all') => {
15
17
  try {
16
18
  const spinner = (0, ora_1.default)('Generating emails preview').start();
17
- await createEmailPreviews(emailDir);
18
- await createStaticFiles(emailDir);
19
+ (0, close_ora_on_sigint_1.closeOraOnSIGNIT)(spinner);
20
+ if (type === 'all' || type === 'templates') {
21
+ await createEmailPreviews(emailDir);
22
+ }
23
+ if (type === 'all' || type === 'static') {
24
+ await createStaticFiles(emailDir);
25
+ }
19
26
  spinner.stopAndPersist({
20
27
  symbol: log_symbols_1.default.success,
21
28
  text: 'Emails preview generated',
@@ -31,9 +38,32 @@ const createEmailPreviews = async (emailDir) => {
31
38
  if (hasEmailsDirectory) {
32
39
  await fs_1.default.promises.rm(constants_1.PACKAGE_EMAILS_PATH, { recursive: true });
33
40
  }
34
- const result = shelljs_1.default.cp('-r', emailDir, constants_1.PACKAGE_EMAILS_PATH);
35
- if (result.code > 0) {
36
- throw new Error(`Something went wrong while copying the file to ${constants_1.PACKAGE_EMAILS_PATH}, ${result.cat()}`);
41
+ const list = glob_1.default.sync(path_1.default.join(emailDir, '/*.{jsx,tsx}'), {
42
+ absolute: true,
43
+ });
44
+ /**
45
+ * instead of copying all files, which would break and js/ts imports,
46
+ * we create placeholder files which just contain the following code:
47
+ *
48
+ * import Mail from '../../path/to/emails/my-template.tsx`
49
+ * export default Mail
50
+ */
51
+ for (const absoluteSrcFilePath of list) {
52
+ const fileName = absoluteSrcFilePath.split('/').pop();
53
+ const targetFile = path_1.default.join(constants_1.PACKAGE_EMAILS_PATH, absoluteSrcFilePath.replace(emailDir, ''));
54
+ 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);
56
+ // if this import is changed, you also need to update `client/src/app/preview/[slug]/page.tsx`
57
+ const sourceCode = `import Mail from '${importFile}';export default Mail;`.replace(';', ';\n');
58
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(targetFile));
59
+ if (fs_extra_1.default.existsSync(targetFile)) {
60
+ if (fs_extra_1.default.readFileSync(targetFile, 'utf8') === sourceCode) {
61
+ // file already exists, no need to trigger a rebuild.
62
+ // can otherwise trigger the next.js rebuild multiple times
63
+ continue;
64
+ }
65
+ }
66
+ await fs_extra_1.default.writeFile(targetFile, sourceCode);
37
67
  }
38
68
  };
39
69
  const createStaticFiles = async (emailDir) => {
@@ -42,7 +72,7 @@ const createStaticFiles = async (emailDir) => {
42
72
  await fs_1.default.promises.rm(constants_1.PACKAGE_PUBLIC_PATH, { recursive: true });
43
73
  }
44
74
  await fs_extra_1.default.ensureDir(path_1.default.join(constants_1.PACKAGE_PUBLIC_PATH, 'static'));
45
- const result = shelljs_1.default.cp('-r', path_1.default.join('static'), path_1.default.join(constants_1.PACKAGE_PUBLIC_PATH));
75
+ const result = shelljs_1.default.cp('-r', path_1.default.join(emailDir, 'static'), path_1.default.join(constants_1.PACKAGE_PUBLIC_PATH));
46
76
  if (result.code > 0) {
47
77
  throw new Error(`Something went wrong while copying the file to ${path_1.default.join(emailDir, 'static')}, ${result.cat()}`);
48
78
  }
@@ -9,8 +9,10 @@ const path_1 = __importDefault(require("path"));
9
9
  const constants_1 = require("./constants");
10
10
  const ora_1 = __importDefault(require("ora"));
11
11
  const log_symbols_1 = __importDefault(require("log-symbols"));
12
+ const close_ora_on_sigint_1 = require("./close-ora-on-sigint");
12
13
  const installDependencies = async (packageManager) => {
13
14
  const spinner = (0, ora_1.default)('Installing dependencies...\n').start();
15
+ (0, close_ora_on_sigint_1.closeOraOnSIGNIT)(spinner);
14
16
  shelljs_1.default.cd(path_1.default.join(constants_1.REACT_EMAIL_ROOT));
15
17
  shelljs_1.default.exec(`${packageManager} install`);
16
18
  spinner.stopAndPersist({
@@ -5,10 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.watcher = exports.createWatcherInstance = void 0;
7
7
  const chokidar_1 = __importDefault(require("chokidar"));
8
- const constants_1 = require("./constants");
9
8
  const fs_1 = __importDefault(require("fs"));
10
9
  const path_1 = __importDefault(require("path"));
11
10
  const shelljs_1 = __importDefault(require("shelljs"));
11
+ const constants_1 = require("./constants");
12
+ const generate_email_preview_1 = require("./generate-email-preview");
12
13
  const createWatcherInstance = (watchDir) => chokidar_1.default.watch(watchDir, {
13
14
  ignoreInitial: true,
14
15
  cwd: watchDir.split(path_1.default.sep).slice(0, -1).join(path_1.default.sep),
@@ -37,9 +38,13 @@ const watcher = (watcherInstance, watchDir) => {
37
38
  }
38
39
  return;
39
40
  }
40
- const result = shelljs_1.default.cp('-r', path_1.default.join(watchDir, ...file.slice(1)), path_1.default.join(constants_1.PACKAGE_EMAILS_PATH, ...file.slice(1, -1)));
41
- if (result.code > 0) {
42
- throw new Error(`Something went wrong while copying the file to ${constants_1.PACKAGE_EMAILS_PATH}, ${result.cat()}`);
41
+ try {
42
+ await (0, generate_email_preview_1.generateEmailsPreview)(watchDir, 'templates');
43
+ }
44
+ catch (e) {
45
+ throw new Error(`Something went wrong while copying the file to ${constants_1.PACKAGE_EMAILS_PATH}, ${
46
+ // @ts-expect-error
47
+ e?.message}`);
43
48
  }
44
49
  });
45
50
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "A live preview of your emails right in your browser.",
5
5
  "bin": {
6
6
  "email": "./dist/source/index.js"
@@ -50,6 +50,7 @@
50
50
  "@types/normalize-path": "3.0.0",
51
51
  "@types/shelljs": "0.8.11",
52
52
  "prettier": "2.7.1",
53
- "ts-node": "10.9.1"
53
+ "ts-node": "10.9.1",
54
+ "typescript": "5.0.4"
54
55
  }
55
56
  }
@@ -9,6 +9,7 @@ import normalize from 'normalize-path';
9
9
  import path from 'path';
10
10
  import shell from 'shelljs';
11
11
  import fs from 'fs';
12
+ import { closeOraOnSIGNIT } from '../utils/close-ora-on-sigint';
12
13
  /*
13
14
  This first builds all the templates using esbuild and then puts the output in the `.js`
14
15
  files. Then these `.js` files are imported dynamically and rendered to `.html` files
@@ -20,6 +21,8 @@ export const exportTemplates = async (
20
21
  options: Options,
21
22
  ) => {
22
23
  const spinner = ora('Preparing files...\n').start();
24
+ closeOraOnSIGNIT(spinner)
25
+
23
26
  const allTemplates = glob.sync(normalize(path.join(srcDir, '*.{tsx,jsx}')));
24
27
 
25
28
  esbuild.buildSync({
@@ -0,0 +1,7 @@
1
+ import { Ora } from 'ora'
2
+
3
+ export const closeOraOnSIGNIT = (spinner: Ora) => {
4
+ process.on('SIGINT', function () {
5
+ spinner.stop()
6
+ });
7
+ }
@@ -9,7 +9,7 @@ export const downloadClient = async () => {
9
9
  const downloadRes = await octokit.repos.downloadTarballArchive({
10
10
  owner: 'resendlabs',
11
11
  repo: 'react-email',
12
- ref: 'v0.0.12',
12
+ ref: 'v0.0.13',
13
13
  });
14
14
  fs.mkdirSync('.react-email-temp');
15
15
  const TAR_PATH = path.join('.react-email-temp', 'react-email.tar.gz');
@@ -5,13 +5,23 @@ import ora from 'ora';
5
5
  import shell from 'shelljs';
6
6
  import path from 'path';
7
7
  import fse from 'fs-extra';
8
+ import glob from 'glob';
9
+ import { closeOraOnSIGNIT } from './close-ora-on-sigint';
8
10
 
9
- export const generateEmailsPreview = async (emailDir: string) => {
11
+ export const generateEmailsPreview = async (
12
+ emailDir: string,
13
+ type: 'all' | 'static' | 'templates' = 'all',
14
+ ) => {
10
15
  try {
11
16
  const spinner = ora('Generating emails preview').start();
17
+ closeOraOnSIGNIT(spinner)
12
18
 
13
- await createEmailPreviews(emailDir);
14
- await createStaticFiles(emailDir);
19
+ if (type === 'all' || type === 'templates') {
20
+ await createEmailPreviews(emailDir);
21
+ }
22
+ if (type === 'all' || type === 'static') {
23
+ await createStaticFiles(emailDir);
24
+ }
15
25
 
16
26
  spinner.stopAndPersist({
17
27
  symbol: logSymbols.success,
@@ -29,12 +39,45 @@ const createEmailPreviews = async (emailDir: string) => {
29
39
  await fs.promises.rm(PACKAGE_EMAILS_PATH, { recursive: true });
30
40
  }
31
41
 
32
- const result = shell.cp('-r', emailDir, PACKAGE_EMAILS_PATH);
42
+ const list = glob.sync(path.join(emailDir, '/*.{jsx,tsx}'), {
43
+ absolute: true,
44
+ });
33
45
 
34
- if (result.code > 0) {
35
- throw new Error(
36
- `Something went wrong while copying the file to ${PACKAGE_EMAILS_PATH}, ${result.cat()}`,
46
+ /**
47
+ * instead of copying all files, which would break and js/ts imports,
48
+ * we create placeholder files which just contain the following code:
49
+ *
50
+ * import Mail from '../../path/to/emails/my-template.tsx`
51
+ * export default Mail
52
+ */
53
+ for (const absoluteSrcFilePath of list) {
54
+ const fileName = absoluteSrcFilePath.split('/').pop()!;
55
+ const targetFile = path.join(
56
+ PACKAGE_EMAILS_PATH,
57
+ absoluteSrcFilePath.replace(emailDir, ''),
58
+ );
59
+ const importPath = path.relative(
60
+ path.dirname(targetFile),
61
+ path.dirname(absoluteSrcFilePath),
37
62
  );
63
+
64
+ const importFile = path.join(importPath, fileName);
65
+
66
+ // if this import is changed, you also need to update `client/src/app/preview/[slug]/page.tsx`
67
+ const sourceCode =
68
+ `import Mail from '${importFile}';export default Mail;`.replace(
69
+ ';',
70
+ ';\n',
71
+ );
72
+ await fse.ensureDir(path.dirname(targetFile));
73
+ if (fse.existsSync(targetFile)) {
74
+ if (fse.readFileSync(targetFile, 'utf8') === sourceCode) {
75
+ // file already exists, no need to trigger a rebuild.
76
+ // can otherwise trigger the next.js rebuild multiple times
77
+ continue;
78
+ }
79
+ }
80
+ await fse.writeFile(targetFile, sourceCode);
38
81
  }
39
82
  };
40
83
 
@@ -49,7 +92,7 @@ const createStaticFiles = async (emailDir: string) => {
49
92
 
50
93
  const result = shell.cp(
51
94
  '-r',
52
- path.join('static'),
95
+ path.join(emailDir, 'static'),
53
96
  path.join(PACKAGE_PUBLIC_PATH),
54
97
  );
55
98
  if (result.code > 0) {
@@ -3,11 +3,13 @@ import path from 'path';
3
3
  import { REACT_EMAIL_ROOT } from './constants';
4
4
  import ora from 'ora';
5
5
  import logSymbols from 'log-symbols';
6
+ import { closeOraOnSIGNIT } from './close-ora-on-sigint';
6
7
 
7
8
  export type PackageManager = 'yarn' | 'npm' | 'pnpm';
8
9
 
9
10
  export const installDependencies = async (packageManager: PackageManager) => {
10
11
  const spinner = ora('Installing dependencies...\n').start();
12
+ closeOraOnSIGNIT(spinner)
11
13
 
12
14
  shell.cd(path.join(REACT_EMAIL_ROOT));
13
15
  shell.exec(`${packageManager} install`);
@@ -1,12 +1,13 @@
1
1
  import chokidar, { FSWatcher } from 'chokidar';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import shell from 'shelljs';
2
5
  import {
3
6
  EVENT_FILE_DELETED,
4
7
  PACKAGE_EMAILS_PATH,
5
8
  REACT_EMAIL_ROOT,
6
9
  } from './constants';
7
- import fs from 'fs';
8
- import path from 'path';
9
- import shell from 'shelljs';
10
+ import { generateEmailsPreview } from './generate-email-preview';
10
11
 
11
12
  export const createWatcherInstance = (watchDir: string) =>
12
13
  chokidar.watch(watchDir, {
@@ -49,14 +50,14 @@ export const watcher = (watcherInstance: FSWatcher, watchDir: string) => {
49
50
  return;
50
51
  }
51
52
 
52
- const result = shell.cp(
53
- '-r',
54
- path.join(watchDir, ...file.slice(1)),
55
- path.join(PACKAGE_EMAILS_PATH, ...file.slice(1, -1)),
56
- );
57
- if (result.code > 0) {
53
+ try {
54
+ await generateEmailsPreview(watchDir, 'templates');
55
+ } catch (e) {
58
56
  throw new Error(
59
- `Something went wrong while copying the file to ${PACKAGE_EMAILS_PATH}, ${result.cat()}`,
57
+ `Something went wrong while copying the file to ${PACKAGE_EMAILS_PATH}, ${
58
+ // @ts-expect-error
59
+ e?.message
60
+ }`,
60
61
  );
61
62
  }
62
63
  });