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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email",
3
- "version": "1.7.4",
3
+ "version": "1.7.6",
4
4
  "description": "A live preview of your emails right in your browser.",
5
5
  "bin": {
6
6
  "email": "./dist/index.js"
@@ -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.9",\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": ">=18.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',
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',
@@ -1 +1,5 @@
1
- export declare const dev: () => Promise<void>;
1
+ interface Args {
2
+ dir: string;
3
+ }
4
+ export declare const dev: ({ dir }: Args) => Promise<void>;
5
+ export {};
@@ -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 utils_1.watcherInstance.close();
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 createStatisFiles();
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)(utils_1.CLIENT_EMAILS_PATH);
132
+ const createEmailPreviews = async (emailDir) => {
133
+ const hasEmailsDirectory = (0, utils_1.checkDirectoryExist)(emailDir);
131
134
  const isEmailsDirectoryEmpty = hasEmailsDirectory
132
- ? await (0, utils_1.checkEmptyDirectory)(utils_1.CLIENT_EMAILS_PATH)
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)(`${utils_1.CLIENT_EMAILS_PATH}/*{.tsx,.jsx}`, utils_1.PACKAGE_EMAILS_PATH);
143
+ await (0, cpy_1.default)(path_1.default.join(emailDir, '*{.tsx,.jsx}'), utils_1.PACKAGE_EMAILS_PATH);
141
144
  };
142
- const createStatisFiles = async () => {
145
+ const createStaticFiles = async (emailDir) => {
143
146
  const hasPackageStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.REACT_EMAIL_ROOT}/public/static`);
144
- const hasStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.CLIENT_EMAILS_PATH}/static`);
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)(`${utils_1.CLIENT_EMAILS_PATH}/static`, `${utils_1.REACT_EMAIL_ROOT}/public/static`);
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 hasComponentsDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.CLIENT_EMAILS_PATH}/components`);
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)(`${utils_1.CLIENT_EMAILS_PATH}/components`, `${utils_1.PACKAGE_EMAILS_PATH}/components`);
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)(`${utils_1.CLIENT_EMAILS_PATH}/*.{tsx,jsx}`));
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 hasStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.CLIENT_EMAILS_PATH}/static`);
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)(`${utils_1.CLIENT_EMAILS_PATH}/static`, `${outDir}/static`);
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,
@@ -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
- .action(dev_1.dev);
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 Text', false)
26
- .action(({ outDir, pretty, plainText }) => (0, export_1.exportTemplates)(outDir, { pretty, plainText }));
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 watcherInstance: chokidar.FSWatcher;
3
- export declare const watcher: () => chokidar.FSWatcher;
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.watcherInstance = void 0;
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
- exports.watcherInstance = chokidar_1.default.watch(constants_1.CLIENT_EMAILS_PATH, {
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
- const watcher = () => exports.watcherInstance.on('all', async (event, filename) => {
18
- if (event === constants_1.EVENT_FILE_DELETED) {
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] === 'static' && file[2]) {
21
- await fs_1.default.promises.rm(path_1.default.join(constants_1.REACT_EMAIL_ROOT, 'public', 'static', file[2]));
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
- await (0, cpy_1.default)(`${constants_1.CLIENT_EMAILS_PATH}/static/${file[2]}`, `${constants_1.REACT_EMAIL_ROOT}/public/static`);
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(constants_1.CURRENT_PATH, filename), path_1.default.join(constants_1.REACT_EMAIL_ROOT, file.slice(0, -1).join(path_1.default.sep)));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email",
3
- "version": "1.7.4",
3
+ "version": "1.7.6",
4
4
  "description": "A live preview of your emails right in your browser.",
5
5
  "bin": {
6
6
  "email": "./dist/index.js"
@@ -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
+ };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email-preview",
3
- "version": "0.0.9",
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": ">=18.0.0"
15
+ "node": ">=16.0.0"
16
16
  },
17
17
  "dependencies": {
18
18
  "@next/font": "13.0.4",
@@ -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.9",\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": ">=18.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',
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',
@@ -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
- export const dev = async () => {
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 createStatisFiles();
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(CLIENT_EMAILS_PATH);
157
+ const createEmailPreviews = async (emailDir: string) => {
158
+ const hasEmailsDirectory = checkDirectoryExist(emailDir);
151
159
 
152
160
  const isEmailsDirectoryEmpty = hasEmailsDirectory
153
- ? await checkEmptyDirectory(CLIENT_EMAILS_PATH)
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(`${CLIENT_EMAILS_PATH}/*{.tsx,.jsx}`, PACKAGE_EMAILS_PATH);
173
+ await copy(path.join(emailDir, '*{.tsx,.jsx}'), PACKAGE_EMAILS_PATH);
166
174
  };
167
175
 
168
- const createStatisFiles = async () => {
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
- `${CLIENT_EMAILS_PATH}/static`,
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
- `${CLIENT_EMAILS_PATH}/static`,
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
- `${CLIENT_EMAILS_PATH}/components`,
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
- `${CLIENT_EMAILS_PATH}/components`,
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, CLIENT_EMAILS_PATH } from '../utils';
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(`${CLIENT_EMAILS_PATH}/*.{tsx,jsx}`),
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
- `${CLIENT_EMAILS_PATH}/static`,
48
+ staticDir
48
49
  );
49
50
 
50
51
  if (hasStaticDirectory) {
51
- await copy(`${CLIENT_EMAILS_PATH}/static`, `${outDir}/static`);
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
- .action(dev);
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 Text', false)
24
- .action(({ outDir, pretty, plainText }) =>
25
- exportTemplates(outDir, { pretty, plainText }),
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();
@@ -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 watcherInstance = chokidar.watch(CLIENT_EMAILS_PATH, {
13
- ignoreInitial: true,
14
- cwd: CURRENT_PATH,
15
- ignored: /(^|[\/\\])\../,
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
- if (event === EVENT_FILE_DELETED) {
21
- const file = filename.split(path.sep);
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
- } else {
32
- const file = filename.split(path.sep);
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
- await copy(
43
- path.join(CURRENT_PATH, filename),
44
- path.join(REACT_EMAIL_ROOT, file.slice(0, -1).join(path.sep)),
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
+ };