|
| 1 | +--- |
| 2 | +title: 'Codebase overview' |
| 3 | +sidebarTitle: 'Codebase overview' |
| 4 | +'og:image': 'https://react.email/static/covers/react-email.png' |
| 5 | +description: 'An overview of the React Email codebase' |
| 6 | +icon: 'folder-tree' |
| 7 | +--- |
| 8 | + |
| 9 | +We've created this guide to help new contributors understand and navigate the React Email codebase. |
| 10 | + |
| 11 | +## Top-level directories |
| 12 | + |
| 13 | +After cloning the [React Email repository](https://github.com/resend/react-email) you will see a few root-level directories. Here's a brief overview of each: |
| 14 | + |
| 15 | +<table> |
| 16 | + <thead> |
| 17 | + <tr> |
| 18 | + <th>Directory</th> |
| 19 | + <th>Description</th> |
| 20 | + </tr> |
| 21 | + </thead> |
| 22 | + <tbody> |
| 23 | + <tr> |
| 24 | + <td> |
| 25 | +[apps](https://github.com/resend/react-email/tree/canary/apps) |
| 26 | + </td> |
| 27 | + <td> |
| 28 | + Here you can find all of the apps related to our online presence, like: |
| 29 | + - this documentation (under [apps/docs](https://github.com/resend/react-email/tree/canary/apps/docs)), |
| 30 | + - the demo emails we have on [demo.react.email](https://demo.react.email/preview/vercel-invite-user.tsx) |
| 31 | + (under [apps/demo](https://github.com/resend/react-email/tree/canary/apps/demo)) |
| 32 | + - the Next app we have for our landing page on [react.email](https://react.email) (under [apps/web](https://github.com/resend/react-email/tree/canary/apps/web)) |
| 33 | + </td> |
| 34 | + </tr> |
| 35 | + <tr> |
| 36 | + <td> |
| 37 | +[benchmarks](https://github.com/resend/react-email/tree/canary/benchmarks) |
| 38 | + </td> |
| 39 | + <td> |
| 40 | + We make benchmarks from version-to-version to demonstrate data-observable performance gains with metrics like *p99 and p75*. |
| 41 | + |
| 42 | + For example, see the [Improved Performance for Tailwind Emails](https://resend.com/blog/improved-performance-for-tailwind-emails) benchmark. |
| 43 | + </td> |
| 44 | + </tr> |
| 45 | + <tr> |
| 46 | + <td> |
| 47 | + [packages](https://github.com/resend/react-email/tree/canary/packages) |
| 48 | + </td> |
| 49 | + <td> |
| 50 | + Most contributions will be made to the packages in this directory. |
| 51 | + |
| 52 | + This directory contains all our published [NPM](https://www.npmjs.com/) packages. |
| 53 | + Each subdirectory is a single component published as its own package, with the exception of a few packages that serve as shared configuration. |
| 54 | + </td> |
| 55 | + </tr> |
| 56 | + </tbody> |
| 57 | +</table> |
| 58 | + |
| 59 | +<Note> |
| 60 | + Feel free to [open a discussion](https://github.com/resend/react-email/discussions/new?category=ideas) if you have suggestions on how to better structure these packages to make them more manageable and approachable. |
| 61 | +</Note> |
| 62 | + |
| 63 | +## Multiple packages |
| 64 | + |
| 65 | +The react-email repository is a [pnpm monorepo](https://pnpm.io/next/workspaces), which means it contains |
| 66 | +multiple packages. |
| 67 | + |
| 68 | +Because we use pnpm, you will need to use [pnpm](https://pnpm.io/) to install and run each package. If you do not have pnpm installed, we recommend you install it using [corepack](https://github.com/nodejs/corepack): |
| 69 | + |
| 70 | +```bash |
| 71 | +corepack enable |
| 72 | +corepack prepare pnpm@latest --activate |
| 73 | +``` |
| 74 | + |
| 75 | +Currently, we have the following packages: |
| 76 | + |
| 77 | +<div className="grid gap-2" style={{ gridTemplateColumns: '1fr 1fr 1fr' }}> |
| 78 | + <div> |
| 79 | + - [@react-email/body](https://github.com/resend/react-email/tree/canary/packages/body) |
| 80 | + - [@react-email/button](https://github.com/resend/react-email/tree/canary/packages/button) |
| 81 | + - [@react-email/code-block](https://github.com/resend/react-email/tree/canary/packages/code-block) |
| 82 | + - [@react-email/code-inline](https://github.com/resend/react-email/tree/canary/packages/code-inline) |
| 83 | + - [@react-email/column](https://github.com/resend/react-email/tree/canary/packages/column) |
| 84 | + - [@react-email/components](https://github.com/resend/react-email/tree/canary/packages/components) |
| 85 | + - [@react-email/container](https://github.com/resend/react-email/tree/canary/packages/container) |
| 86 | + - [create-email](https://github.com/resend/react-email/tree/canary/packages/create-email) |
| 87 | + - <span className="text-xs">Used for our [automatic setup](/getting-started/automatic-setup)</span> |
| 88 | + </div> |
| 89 | + <div> |
| 90 | + - [@react-email/font](https://github.com/resend/react-email/tree/canary/packages/font) |
| 91 | + - [@react-email/head](https://github.com/resend/react-email/tree/canary/packages/head) |
| 92 | + - [@react-email/heading](https://github.com/resend/react-email/tree/canary/packages/heading) |
| 93 | + - [@react-email/hr](https://github.com/resend/react-email/tree/canary/packages/hr) |
| 94 | + - [@react-email/html](https://github.com/resend/react-email/tree/canary/packages/html) |
| 95 | + - [@react-email/img](https://github.com/resend/react-email/tree/canary/packages/img) |
| 96 | + - [@react-email/link](https://github.com/resend/react-email/tree/canary/packages/link) |
| 97 | + - [@react-email/markdown](https://github.com/resend/react-email/tree/canary/packages/markdown) |
| 98 | + - [@react-email/preview](https://github.com/resend/react-email/tree/canary/packages/preview) |
| 99 | + </div> |
| 100 | + <div> |
| 101 | + - [react-email](https://github.com/resend/react-email/tree/canary/packages/react-email) |
| 102 | + - <span className="text-xs">The package for our [email CLI](/cli)</span> |
| 103 | + - [@react-email/render](https://github.com/resend/react-email/tree/canary/packages/render) |
| 104 | + - [@react-email/row](https://github.com/resend/react-email/tree/canary/packages/row) |
| 105 | + - [@react-email/section](https://github.com/resend/react-email/tree/canary/packages/section) |
| 106 | + - [@react-email/tailwind](https://github.com/resend/react-email/tree/canary/packages/tailwind) |
| 107 | + - [@react-email/text](https://github.com/resend/react-email/tree/canary/packages/text) |
| 108 | + </div> |
| 109 | +</div> |
| 110 | + |
| 111 | +Most of these packages are very small and can be easily understood by reading the code, so feel free to explore. |
| 112 | + |
| 113 | +### Turborepo |
| 114 | + |
| 115 | +We encourage using [turborepo](https://turbo.build/repo) to manage the packages. |
| 116 | + |
| 117 | +It's often helpful to [install Turborepo globally](https://turbo.build/repo/docs/installing) to make it easier to run commands in any of the repositories. With a global installation, running `turbo build` in any of the packages will build both the package |
| 118 | +you are on as well as the dependent packages. The global installation handles [version mismatching as well](https://turbo.build/repo/docs/installing#install-per-repository). |
| 119 | + |
| 120 | +### The React Email CLI |
| 121 | + |
| 122 | +The CLI (i.e. `packages/react-email`) is key to the best development experience with react.email, but it is complex. Here is a brief overview of the CLI. |
| 123 | + |
| 124 | +The CLI includes two components: |
| 125 | +- A Next app for the `email dev` and `email build` commands |
| 126 | +- A [commander.js](https://www.npmjs.com/package/commander) CLI |
| 127 | + |
| 128 | +In the NextJS app, we include a `src/cli` directory that is not published but is compiled into a root `cli` directory. This structure provides a good developer experience as we can both share certain functions and communicate between the CLI components. |
| 129 | + |
| 130 | +We trigger rebuilds of email templates after they have been saved using the |
| 131 | +[chokidar](https://www.npmjs.com/package/chokidar) package |
| 132 | +alongside the [socket.io](https://socket.io/) package to detect file changes and send |
| 133 | +a message to the server to trigger a rebuild. |
| 134 | + |
| 135 | +## Testing |
| 136 | + |
| 137 | +For testing, we use [vitest](https://vitest.dev/). We prefer to define globals and run tests under the `happy-dom` environment. |
| 138 | + |
| 139 | +We do not strictly enforce testing coverage, but encourage it. |
| 140 | + |
| 141 | +For help testing, see our [Development workflow guide](/contributing/development-workflow/2-running-tests). |
| 142 | + |
| 143 | +<Note> |
| 144 | +The `@react-email/render` package's `renderAsync` does a fair bit of magic to simulate `edge` and other environments that are not supported by `happy-dom`. For this use case, we override the [environment on a per-file basis](https://vitest.dev/guide/environment#environments-for-specific-files) for its tests |
| 145 | +</Note> |
| 146 | + |
| 147 | +## Linting |
| 148 | + |
| 149 | +We use [biomejs](https://biomejs.dev/) for linting and formatting. Both the linting and formatting are ensured by our GitHub CI so make sure you lint and format your code (`pnpm lint:fix`) before opening a PR or asking for a review on it. |
| 150 | + |
| 151 | +For help linting and formatting, see our [Development workflow guide on linting](/contributing/development-workflow/3-linting). |
| 152 | + |
| 153 | +## Building |
| 154 | + |
| 155 | +We use [tsup](https://github.com/egoist/tsup) to build most packages. (The only exception for this is the `@react-email/tailwind` package which currently uses `vite` due to a few issues with `tsup` and `tailwindcss`'s bundling.) For help building packages, see our [Development workflow guide](/contributing/development-workflow/4-building). |
| 156 | + |
| 157 | +<Note> |
| 158 | +Building in each package will run `tsup` with a few settings, typically `src/index.ts --format esm,cjs --dts --external react`. |
| 159 | +Tsup handles building both ESM and CJS versions along with the type definitions exported from the entry point, `src/index.ts`, without bundling `react`, which can cause issues. |
| 160 | +</Note> |
| 161 | + |
| 162 | +### Why build before publishing? |
| 163 | + |
| 164 | +We build most of the packages before publishing for a few reasons: |
| 165 | + |
| 166 | +1. All the exported types can be imported from the same place the JavaScript is imported |
| 167 | +2. We have proper [CommonJS](https://nodejs.org/docs/latest/api/modules.html#modules-commonjs-modules) |
| 168 | +and [ES Modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) support |
| 169 | +3. Code that isn't exported is not published or downloaded |
0 commit comments