-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cli): Setup command for mailer (#9335)
**Description** Mailer will be available from a setup command: `yarn rw setup mailer`. This PR adds that command. Like all good PRs this also does a second thing. This adds functionality to the mailer which enables it to conditionally use an in-memory handler for test and the studio handler for development if those dependencies are available. This is essentially adding automatic defaults but respecting if the dependencies are available. **Changes** 1. Adds a setup command: `yarn rw setup mailer` 2. Implements fallback/default dev & test handlers for when the user has not set specific configuration. **Notes** 1. I'm not overly thrilled with the typing/implementation of these automatic/fallback test/dev handlers but we can improve that going forward. **Future work** 1. We should improve the logging output. 2. I NEED to write the docs now. --------- Co-authored-by: David Thyresson <[email protected]>
- Loading branch information
Showing
7 changed files
with
328 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers' | ||
|
||
export const command = 'mailer' | ||
|
||
export const description = | ||
'Setup the redwood mailer. This will install the required packages and add the required initial configuration to your redwood app.' | ||
|
||
export const builder = (yargs) => { | ||
yargs | ||
.option('force', { | ||
alias: 'f', | ||
default: false, | ||
description: 'Overwrite existing configuration', | ||
type: 'boolean', | ||
}) | ||
.option('skip-examples', { | ||
default: false, | ||
description: 'Only include required files and exclude any examples', | ||
type: 'boolean', | ||
}) | ||
} | ||
|
||
export const handler = async (options) => { | ||
recordTelemetryAttributes({ | ||
command: 'setup mailer', | ||
force: options.force, | ||
skipExamples: options.skipExamples, | ||
}) | ||
const { handler } = await import('./mailerHandler.js') | ||
return handler(options) | ||
} |
119 changes: 119 additions & 0 deletions
119
packages/cli/src/commands/setup/mailer/mailerHandler.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
|
||
import { Listr } from 'listr2' | ||
|
||
import { addApiPackages } from '@redwoodjs/cli-helpers' | ||
import { errorTelemetry } from '@redwoodjs/telemetry' | ||
|
||
import { getPaths, transformTSToJS, writeFile } from '../../../lib' | ||
import c from '../../../lib/colors' | ||
import { isTypeScriptProject } from '../../../lib/project' | ||
|
||
export const handler = async ({ force, skipExamples }) => { | ||
const projectIsTypescript = isTypeScriptProject() | ||
const redwoodVersion = | ||
require(path.join(getPaths().base, 'package.json')).devDependencies[ | ||
'@redwoodjs/core' | ||
] ?? 'latest' | ||
|
||
const tasks = new Listr( | ||
[ | ||
{ | ||
title: `Adding api/src/lib/mailer.${ | ||
projectIsTypescript ? 'ts' : 'js' | ||
}...`, | ||
task: () => { | ||
const templatePath = path.resolve( | ||
__dirname, | ||
'templates', | ||
'mailer.ts.template' | ||
) | ||
const templateContent = fs.readFileSync(templatePath, { | ||
encoding: 'utf8', | ||
flag: 'r', | ||
}) | ||
|
||
const mailerPath = path.join( | ||
getPaths().api.lib, | ||
`mailer.${projectIsTypescript ? 'ts' : 'js'}` | ||
) | ||
const mailerContent = projectIsTypescript | ||
? templateContent | ||
: transformTSToJS(mailerPath, templateContent) | ||
|
||
return writeFile(mailerPath, mailerContent, { | ||
overwriteExisting: force, | ||
}) | ||
}, | ||
}, | ||
{ | ||
title: 'Adding api/src/mail directory...', | ||
task: () => { | ||
const mailDir = path.join(getPaths().api.mail) | ||
if (!fs.existsSync(mailDir)) { | ||
fs.mkdirSync(mailDir) | ||
} | ||
}, | ||
}, | ||
{ | ||
title: `Adding example ReactEmail mail template`, | ||
skip: () => skipExamples, | ||
task: () => { | ||
const templatePath = path.resolve( | ||
__dirname, | ||
'templates', | ||
're-example.tsx.template' | ||
) | ||
const templateContent = fs.readFileSync(templatePath, { | ||
encoding: 'utf8', | ||
flag: 'r', | ||
}) | ||
|
||
const exampleTemplatePath = path.join( | ||
getPaths().api.mail, | ||
'Example', | ||
`Example.${projectIsTypescript ? 'tsx' : 'jsx'}` | ||
) | ||
const exampleTemplateContent = projectIsTypescript | ||
? templateContent | ||
: transformTSToJS(exampleTemplatePath, templateContent) | ||
|
||
return writeFile(exampleTemplatePath, exampleTemplateContent, { | ||
overwriteExisting: force, | ||
}) | ||
}, | ||
}, | ||
{ | ||
// Add production dependencies | ||
...addApiPackages([ | ||
`@redwoodjs/mailer-core@${redwoodVersion}`, | ||
`@redwoodjs/mailer-handler-nodemailer@${redwoodVersion}`, | ||
`@redwoodjs/mailer-renderer-react-email@${redwoodVersion}`, | ||
`@react-email/components`, // NOTE: Unpinned dependency here | ||
]), | ||
title: 'Adding production dependencies to your api side...', | ||
}, | ||
{ | ||
// Add development dependencies | ||
...addApiPackages([ | ||
'-D', | ||
`@redwoodjs/mailer-handler-in-memory@${redwoodVersion}`, | ||
`@redwoodjs/mailer-handler-studio@${redwoodVersion}`, | ||
]), | ||
title: 'Adding development dependencies to your api side...', | ||
}, | ||
], | ||
{ | ||
rendererOptions: { collapseSubtasks: false }, | ||
} | ||
) | ||
|
||
try { | ||
await tasks.run() | ||
} catch (e) { | ||
errorTelemetry(process.argv, e.message) | ||
console.error(c.error(e.message)) | ||
process.exit(e?.exitCode || 1) | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
packages/cli/src/commands/setup/mailer/templates/mailer.ts.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Mailer } from '@redwoodjs/mailer-core' | ||
import { NodemailerMailHandler } from '@redwoodjs/mailer-handler-nodemailer' | ||
import { ReactEmailRenderer } from '@redwoodjs/mailer-renderer-react-email' | ||
|
||
import { logger } from 'src/lib/logger' | ||
|
||
export const mailer = new Mailer({ | ||
handling: { | ||
handlers: { | ||
// TODO: Update this handler config or switch it out for a different handler completely | ||
nodemailer: new NodemailerMailHandler({ | ||
transport: { | ||
host: 'localhost', | ||
port: 4319, | ||
secure: false, | ||
}, | ||
}), | ||
}, | ||
default: 'nodemailer', | ||
}, | ||
|
||
rendering: { | ||
renderers: { | ||
reactEmail: new ReactEmailRenderer(), | ||
}, | ||
default: 'reactEmail', | ||
}, | ||
|
||
logger, | ||
}) |
40 changes: 40 additions & 0 deletions
40
packages/cli/src/commands/setup/mailer/templates/re-example.tsx.template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import React from 'react' | ||
|
||
import { | ||
Html, | ||
Text, | ||
Hr, | ||
Body, | ||
Head, | ||
Tailwind, | ||
Preview, | ||
Container, | ||
Heading, | ||
} from '@react-email/components' | ||
|
||
export function ExampleEmail( | ||
{ when }: { when: string } = { when: new Date().toLocaleString() } | ||
) { | ||
return ( | ||
<Html lang="en"> | ||
<Head /> | ||
<Preview>An example email</Preview> | ||
<Tailwind> | ||
<Body className="mx-auto my-auto bg-white font-sans"> | ||
<Container className="mx-auto my-[40px] rounded border border-solid border-gray-200 p-[20px]"> | ||
<Heading className="mx-0 my-[30px] p-0 text-center text-[24px] font-normal text-black"> | ||
Example Email | ||
</Heading> | ||
<Text className="text-[14px] leading-[24px] text-black"> | ||
This is an example email which you can customise to your needs. | ||
</Text> | ||
<Hr className="mx-0 my-[26px] w-full border border-solid border-[#eaeaea]" /> | ||
<Text className="text-[12px] leading-[24px] text-[#666666]"> | ||
Message was sent on {when} | ||
</Text> | ||
</Container> | ||
</Body> | ||
</Tailwind> | ||
</Html> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.