diff --git a/.changeset/custom-extension-cli.md b/.changeset/custom-extension-cli.md new file mode 100644 index 0000000000..fe32ceba9a --- /dev/null +++ b/.changeset/custom-extension-cli.md @@ -0,0 +1,5 @@ +--- +"react-email": minor +--- + +Enable custom export extensions via --extension/-e (e.g. .blade.php). diff --git a/apps/docs/cli.mdx b/apps/docs/cli.mdx index 1651ca0342..7590eaaace 100644 --- a/apps/docs/cli.mdx +++ b/apps/docs/cli.mdx @@ -190,6 +190,10 @@ Generates the plain HTML files of your emails into a `out` directory. Change the directory of your email templates. + + Set a custom file extension for rendered templates (for example, `blade.php`). When omitted, + the extension defaults to `.html`, or `.txt` when `--plainText` is enabled. + ## `email help ` diff --git a/packages/react-email/src/commands/export.ts b/packages/react-email/src/commands/export.ts index 1086bd4adf..b77be35935 100644 --- a/packages/react-email/src/commands/export.ts +++ b/packages/react-email/src/commands/export.ts @@ -30,6 +30,7 @@ const getEmailTemplatesFromDirectory = (emailDirectory: EmailsDirectory) => { }; type ExportTemplatesOptions = Options & { + extension?: string; silent?: boolean; pretty?: boolean; }; @@ -115,6 +116,15 @@ export const exportTemplates = async ( }, ); + const extension = + options.extension && options.extension.length > 0 + ? options.extension.startsWith('.') + ? options.extension + : `.${options.extension}` + : options.plainText + ? '.txt' + : '.html'; + for await (const template of allBuiltTemplates) { try { if (spinner) { @@ -134,10 +144,7 @@ export const exportTemplates = async ( emailModule.reactEmailCreateReactElement(emailModule.default, {}), options, ); - const htmlPath = template.replace( - '.cjs', - options.plainText ? '.txt' : '.html', - ); + const htmlPath = template.replace('.cjs', extension); writeFileSync(htmlPath, rendered); unlinkSync(template); } catch (exception) { diff --git a/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap b/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap index 615acfb5ad..9304056de9 100644 --- a/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap +++ b/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap @@ -195,3 +195,199 @@ exports[`email export 1`] = ` " `; + +exports[`email export with custom extension 1`] = ` +" + + + + + + + + + + + + + + + +
+
+ Join undefined on Vercel +
+  ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ +
+
+ + + + + + +
+ + + + + + +
+ Vercel Logo +
+

+ Join on Vercel +

+

+ Hello + , +

+

+ () has invited you to the team on + Vercel. +

+ + + + + + +
+ + + + + + + + +
+ undefined's profile picture + + Arrow indicating invitation + + undefined team logo +
+
+ + + + + + +
+ Join the team +
+

+ or copy and paste this URL into your browser: + +

+
+

+ This invitation was intended for + . This invite was + sent from + located in + . If you were not + expecting this invitation, you can ignore this email. If + you are concerned about your account's safety, please + reply to this email to get in touch with us. +

+
+
+ + + +" +`; diff --git a/packages/react-email/src/commands/testing/export.spec.ts b/packages/react-email/src/commands/testing/export.spec.ts index 0f688b30ab..ea7075f449 100644 --- a/packages/react-email/src/commands/testing/export.spec.ts +++ b/packages/react-email/src/commands/testing/export.spec.ts @@ -18,3 +18,22 @@ test('email export', { retry: 3 }, async () => { ), ).toMatchSnapshot(); }); + +test('email export with custom extension', { retry: 3 }, async () => { + const pathToEmailsDirectory = path.resolve(__dirname, './emails'); + const pathToDumpMarkup = path.resolve(__dirname, './out'); + + await exportTemplates(pathToDumpMarkup, pathToEmailsDirectory, { + silent: true, + pretty: true, + extension: 'blade.php', + }); + + const outputFile = path.resolve( + pathToDumpMarkup, + './vercel-invite-user.blade.php', + ); + + expect(fs.existsSync(outputFile)).toBe(true); + expect(await fs.promises.readFile(outputFile, 'utf8')).toMatchSnapshot(); +}); diff --git a/packages/react-email/src/index.ts b/packages/react-email/src/index.ts index 43f4fba483..c9b8ea862b 100644 --- a/packages/react-email/src/index.ts +++ b/packages/react-email/src/index.ts @@ -43,13 +43,17 @@ program .option('-p, --pretty', 'Pretty print the output', false) .option('-t, --plainText', 'Set output format as plain text', false) .option('-d, --dir ', 'Directory with your email templates', './emails') + .option( + '-e, --extension ', + 'Set a custom file extension for rendered emails (e.g. blade.php)', + ) .option( '-s, --silent', 'To, or not to show a spinner with process information', false, ) - .action(({ outDir, pretty, plainText, silent, dir: srcDir }) => - exportTemplates(outDir, srcDir, { silent, plainText, pretty }), + .action(({ outDir, pretty, plainText, silent, dir: srcDir, extension }) => + exportTemplates(outDir, srcDir, { silent, plainText, pretty, extension }), ); program.parse();