Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): Improved contributing guide #1342

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
457a6d0
chore: Make the CONTRIBUTING.md point towards the docs contributing g…
gabrielmfern Feb 19, 2024
75c7dd6
chore(docs): Rename contributing page to "Old contributing" on the si…
gabrielmfern Feb 19, 2024
5877376
feat(docs): Add new codebase overview (WIP) and opening issues page a…
gabrielmfern Feb 19, 2024
2f2f429
WIP: closer to finishing the write-up for the codebase overview
gabrielmfern Feb 19, 2024
20820f1
feat(docs/contributing): linting, testing and a few other sections on…
gabrielmfern Feb 20, 2024
50219d3
feat(docs/contributing): Conclusion with "New issue" button
gabrielmfern Feb 20, 2024
791d925
chore(docs/contributing): Add icon to codebase-overview
gabrielmfern Feb 20, 2024
b762e8f
feat(docs/contributing): List all packages inside of a table
gabrielmfern Feb 20, 2024
81ce69d
feat(docs/contributing): A grid of lists for all the packages
gabrielmfern Feb 20, 2024
ba3002e
feat(docs/contributing): Development workflow with 1. Setup done
gabrielmfern Feb 20, 2024
2d07202
feat(docs/contributing): 2. Running tests
gabrielmfern Feb 20, 2024
0ca238b
feat(docs/contributing): 3. Linting the project
gabrielmfern Feb 20, 2024
e985ca5
feat(docs/contributing): 4. Building on the development workflow
gabrielmfern Feb 20, 2024
3065fe5
feat(docs/contributing): Add ## building to the codebase-overview
gabrielmfern Feb 20, 2024
935a67f
fet(docs/contributing): Opening pull requests section
gabrielmfern Feb 20, 2024
21edf42
fix(docs): Invalid property "class" warning
gabrielmfern Mar 5, 2024
66f0ebc
chore(docs/development-workflow): Small note on the `pnpm build` step
gabrielmfern Mar 5, 2024
1b155a9
fix(docs): grammar on the "Opening issues" page
gabrielmfern Mar 5, 2024
11e7963
feat(docs): Section for writing a good description for pull requests
gabrielmfern Mar 5, 2024
16ab07c
fix(docs): Gramamr on the "building" in the development workflow
gabrielmfern Mar 5, 2024
f2fb101
fix(docs): Grammar on the "Opening pull requests" page
gabrielmfern Mar 5, 2024
b5c9cb1
chore(docs): Format
gabrielmfern Mar 5, 2024
c4fb375
fix(root): broken link to the contributing guide on the docs
gabrielmfern Mar 5, 2024
8dd27a3
feat(docs): Another argument for making a proper reproduction
gabrielmfern Mar 27, 2024
e9b5939
fix(docs): Grammar based on the context
gabrielmfern Mar 27, 2024
399c465
a few writing improvements on the opening issues section
gabrielmfern Jun 4, 2024
a2becc2
remove uneeded extra reason for why we build
gabrielmfern Jun 20, 2024
9354e48
a few writing improvements on the linting for the development workflow
gabrielmfern Jun 20, 2024
f7101d5
improve writing in the running tests step
gabrielmfern Jun 20, 2024
eb3f714
add mention that issues that have been fixed under canary should stil…
gabrielmfern Jun 20, 2024
d2f5ba3
add mention that docs pull requests should go onto main
gabrielmfern Jun 20, 2024
a6de5f7
add that the guidelines for PR descriptions are not required
gabrielmfern Jun 20, 2024
d27c164
add section for writing docs in the dev workflow
gabrielmfern Jun 20, 2024
28f35d5
remove old contribution navigation item
gabrielmfern Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 1 addition & 28 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,28 +1 @@
## Contributing

Wanna help? Awesome! There are many ways you can contribute.

## Improving the docs

Documentation is extremely important and takes a fair deal of time and effort to write and keep updated. Everything is written in Markdown to facilitate the process of contributing.

## Building new components

We’re open to expanding the catalog of components to cover as many use cases as possible. We suggest to open an issue for discussion first to make sure your idea is aligned with the project goals.

## Opening issues

Open an issue to report bugs or to propose new features.

**- Reporting bugs:**
describe the bug as clearly as you can, including steps to reproduce, what happened and what you were expecting to happen. Also include browser version, OS and other related software’s (npm, Node.js, etc) versions when applicable.

**- Suggesting features:** explain the proposed feature, what it should do, why it is useful, how users should use it. Give us as much info as possible so it will be easier to discuss, access and implement the proposed feature. When you’re unsure about a certain aspect of the feature, feel free to leave it open for others to discuss and find an appropriate solution.

## Proposing pull requests

Pull requests are very welcome. Note that if you are going to propose drastic changes, be sure to open an issue for discussion first, to make sure that your PR will be accepted before you spend effort coding it.

**- Forking the repository:** clone it locally and create a branch for your proposed bug fix or new feature. Avoid working directly on the main branch.

**- Making changes:** implement your bug fix or feature, write tests to cover it and make sure all tests are passing. Then commit your changes, push your bug fix/feature branch to the origin (your forked repo) and open a pull request to the upstream (the repository you originally forked)‘s main branch.
See https://react.email/docs/contributing/codebase-overview
2 changes: 1 addition & 1 deletion apps/docs/contributing.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 'Contributing'
sidebarTitle: 'Contributing'
sidebarTitle: 'Old Contributing'
description: 'Wanna help? Awesome! There are many ways you can contribute.'
'og:image': 'https://react.email/static/covers/react-email.png'
icon: 'code-pull-request'
Expand Down
214 changes: 214 additions & 0 deletions apps/docs/contributing/codebase-overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
---
title: 'Codebase overview'
sidebarTitle: 'Codebase overview'
'og:image': 'https://react.email/static/covers/react-email.png'
description: 'A section to make the React Email codebase more approachable'
icon: 'folder-tree'
---

Try reading this section if you feel like the amount of directories or files are cumbersome
or if you can't understand what is what.

## Top-level directories

After cloning the [React Email repository](https://github.com/resend/react-email) you will
be able to see a few directories at the root:

<table>
<thead>
<tr>
<th>Directory</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
[apps](https://github.com/resend/react-email/tree/canary/apps)
</td>
<td>
Here you can find all of the apps related to our online presence, like:
- this documentation (under [apps/docs](https://github.com/resend/react-email/tree/canary/apps/docs)),
- the demo emails we have on [demo.react.email](https://demo.react.email/preview/vercel-invite-user.tsx)
(under [apps/demo](https://github.com/resend/react-email/tree/canary/apps/demo))
- 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))
</td>
</tr>
<tr>
<td>
[benchmarks](https://github.com/resend/react-email/tree/canary/benchmarks)
</td>
<td>
These are meant to be benchmarks we make from version-to-version to demonstrate with actual
data that performance gains are really true with metrics like *p99 and p75*.

One example of them is the one for the [Improved Performance for Tailwind Emails](https://resend.com/blog/improved-performance-for-tailwind-emails)
</td>
</tr>
<tr>
<td>
[packages](https://github.com/resend/react-email/tree/canary/packages)
</td>
<td>
This is probably where you are going to spend the majority of your time if you are going to contribute.

It contains all the [NPM](https://www.npmjs.com/) published packages that we currently have,
each directory should be one of these, with the exception of [a few of them]()
that are meant for shared configuration but you shouldn't have to worry about them in
the vast majority of cases.
</td>
</tr>
</tbody>
</table>

<Note>
If you have an idea of a better way we could structure these packages so that they could
be more manageable and approachable we would really appreciate you
[create a discussion](https://github.com/resend/react-email/discussions/new?category=ideas) with your thoughts
on this.
</Note>

## Multiple packages

This repository is a [pnpm monorepo](https://pnpm.io/next/workspaces) which means it contains
multiple packages that are maintained. We keep each component we make inside of a package for itself.
This being a pnpm monorepo means you need to use [pnpm](https://pnpm.io/) to install the packages
and we recommend you do so by using [corepack](https://github.com/nodejs/corepack) as follows:

```bash
corepack enable
corepack prepare pnpm@latest --activate
```

Currently we have the following packages:

<div className="grid gap-2" style={{ gridTemplateColumns: '1fr 1fr 1fr' }}>
<div>
- [@react-email/body](https://github.com/resend/react-email/tree/canary/packages/body)
- [@react-email/button](https://github.com/resend/react-email/tree/canary/packages/button)
- [@react-email/code-block](https://github.com/resend/react-email/tree/canary/packages/code-block)
- [@react-email/code-inline](https://github.com/resend/react-email/tree/canary/packages/code-inline)
- [@react-email/column](https://github.com/resend/react-email/tree/canary/packages/column)
- [@react-email/components](https://github.com/resend/react-email/tree/canary/packages/components)
- [@react-email/container](https://github.com/resend/react-email/tree/canary/packages/container)
- [create-email](https://github.com/resend/react-email/tree/canary/packages/create-email)
- <span className="text-xs">Used for our [automatic setup](/getting-started/automatic-setup)</span>
</div>
<div>
- [@react-email/font](https://github.com/resend/react-email/tree/canary/packages/font)
- [@react-email/head](https://github.com/resend/react-email/tree/canary/packages/head)
- [@react-email/heading](https://github.com/resend/react-email/tree/canary/packages/heading)
- [@react-email/hr](https://github.com/resend/react-email/tree/canary/packages/hr)
- [@react-email/html](https://github.com/resend/react-email/tree/canary/packages/html)
- [@react-email/img](https://github.com/resend/react-email/tree/canary/packages/img)
- [@react-email/link](https://github.com/resend/react-email/tree/canary/packages/link)
- [@react-email/markdown](https://github.com/resend/react-email/tree/canary/packages/markdown)
- [@react-email/preview](https://github.com/resend/react-email/tree/canary/packages/preview)
</div>
<div>
- [react-email](https://github.com/resend/react-email/tree/canary/packages/react-email)
- <span className="text-xs">The package for our [email CLI](/cli)</span>
- [@react-email/render](https://github.com/resend/react-email/tree/canary/packages/render)
- [@react-email/row](https://github.com/resend/react-email/tree/canary/packages/row)
- [@react-email/section](https://github.com/resend/react-email/tree/canary/packages/section)
- [@react-email/tailwind](https://github.com/resend/react-email/tree/canary/packages/tailwind)
- [@react-email/text](https://github.com/resend/react-email/tree/canary/packages/text)
</div>
</div>

Don't be scared by the amount of packages as most of them are quite small, with <br/>[the largest
component package](https://github.com/resend/react-email/tree/canary/packages/tailwind) being only 900 lines of code.
And the largest one being the CLI itself which is actually two things in one, more [information on that later](#the-package-for-our-cli-i-e-packages-react-email).


### Turborepo

For managing the tasks that you might want to run on all of the packages we use [turborepo](https://turbo.build/repo)
it does so in parallel and won't re-run already ran code which makes it really fast after initial the run.

If you want to use `turborepo` on the projects you can just use the root scripts we have defined
that directly calls into turborepo and you can see them on the `package.json` file.

Even though you don't need it, we do recommend you have it [installed globally](https://turbo.build/repo/docs/installing)
as it allows you to go into one of the packages and run something like `turbo build` which will build both the package
you are on, as well as the packages it depends on. Very useful for testing to make sure things are working as expected.

Also, don't worry about installing it globally and it version mismatching with the one we have in the repo,
as [turborepo also deals with that](https://turbo.build/repo/docs/installing#install-per-repository).


### The package for our CLI (i.e. `packages/react-email`)

The CLI is one of the most important pieces for the best development we can provide to users,
it can both cause the biggest amount of pain, during development, as well as increase the user's
speed by quite a lot. Besides that, it's also one of our most complicated packages so let's go over it a bit.

The CLI is both a Next app, for the `email dev` and `email build` commands,
as well as a [commander.js]((https://www.npmjs.com/package/commander)) CLI.
The way we are able to do this is by just having a common Next app file structure and then
including a sneaky `src/cli` directory that is not published and is compiled into a root `cli` directory.

This allows for a really good developer experience as we can both share certain functions, as well
as communicate between them without that much of an issue.

For triggering rebuilds of email templates after they have been saved we use the
[chokidar](https://www.npmjs.com/package/chokidar) package
alongside the [socket.io](https://socket.io/) package to detect file changes and send
a message to the server that then triggers a rebuild respectively.



## Testing

For testing we use [vitest](https://vitest.dev/) for its really awesome speed and simplicity,
we prefer it with its globals defined and all the tests are ran under the `happy-dom` environment.

This of course, with the exception of the `@react-email/render` package's `renderAsync` that
does a fair bit of magic to simulate `edge` and other environments that are not supported by `happy-dom`.
For this we override the
[environment on a per-file basis](https://vitest.dev/guide/environment#environments-for-specific-files) for its tests

We don't have a very strict policy about testing coverage, but we do try to keep things tested to avoid
both regressions and to make sure that the code is working as expected. A good rule of thumb is that
if you need to simulate use cases to just test a specific portion of code, you should probably have that
split into a function

## Linting

We use [eslint](https://eslint.org/) for linting, and we have a private unpublished package
called <br/>`eslint-config-custom` that we share across packages and apps. This package is not meant to be
used outside the repository and is not published to npm.

For each type of project we have a different configuration to extend and use from the shared configuration,
they are all based on the [Vercel Engineering Style Guide](https://github.com/vercel/style-guide).
If you want to run linting check on a specific package they all have a `lint` script that you can run
with <br/>`pnpm lint`.

We also use [prettier](https://prettier.io/) for formatting, and we have just one configuration
for all the projects on the root of the repo, if you want to use it you can just run `pnpm format`
at the root of the repository, and it will do so throughout the project.

Both the linting and formatting are ensured by our GitHub CI so make sure that you have your linting
and formatting right before you get to opening a PR or asking for a review on it.

## Building

What we currently use, for the most part, is the awesome [tsup](https://github.com/egoist/tsup).
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.

This will literally run `tsup` with a few settings we have for it. Generally
they are just `src/index.ts --format esm,cjs --dts --external react` which
generates both an ESM and CJS versions of the package and the type definitions
that were exported from `src/index.ts`, which is the entry point. `--external
react` here ensures that `react` is not bundled in which can cause many issues.

### Why build before publishing?

Currently, we do building for most of the packages. This is important for a few key reasons
that improve the usability of each package:

1. All the exported types can be imported from the same place the JavaScript is imported
2. We have proper [CommonJS](https://nodejs.org/docs/latest/api/modules.html#modules-commonjs-modules)
and [ES Modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) support
3. Code that isn't exported is not published nor downloaded
43 changes: 43 additions & 0 deletions apps/docs/contributing/development-workflow/1-setup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: 'Setup'
sidebarTitle: '1. Setup'
'og:image': 'https://react.email/static/covers/react-email.png'
description: 'Things you will need to do beforehand to setup the project'
---

Before you can start actually developing you will have to understand
a few things and get things setup so that you can get to what you need to do.

First things first, make sure you are using the same Node version as we are, at least **Node 18**.

Then, after you do have the right Node version, let's go over the setup for development.

<Steps>
<Step title="Clone the repository">
```bash
git clone https://github.com/resend/react-email
```
</Step>
<Step title={<>Enable <a href="https://pnpm.io/">pnpm</a> through <a href="https://github.com/nodejs/corepack">corepack</a></>}>
```bash inside of react-email
corepack enable
corepack prepare pnpm@latest --activate
```
</Step>
<Step title="Install all the dependencies">
```bash inside of react-email
pnpm install
```
</Step>
<Step title="Build all the packages">
```bash inside of react-email
pnpm build
```

It's important to run this because each package may depend on other packages,
so having them pre-built may save you a bit of headache.
</Step>
</Steps>

This should have you set up and running without any issues, If you do have any issues
please [open up an issue on GitHub](https://github.com/resend/react-email/issues/new?assignees=&labels=Type%3A+Bug&projects=&template=1.bug_report.yml).
31 changes: 31 additions & 0 deletions apps/docs/contributing/development-workflow/2-running-tests.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: 'Running tests'
sidebarTitle: '2. Running tests'
'og:image': 'https://react.email/static/covers/react-email.png'
description: 'What we use for testing and how you can run them reliably'
---

For testing we use [Vitest](https://vitest.dev/) for its really awesome speed
and simplicity, we prefer it with its globals defined and all the tests are ran
under the `happy-dom` environment.

After you have gone through the
[setup](/contributing/development-workflow/2-running-tests) you can just run
`pnpm test` inside any package. This will run the tests only once. We have two
scripts defined on our packages for testing:

- `pnpm test`: Runs all the tests once, if ran on the root it will run the
tests for all packages using
[turborepo](/contributing/codebase-overview#turborepo)
- `pnpm test:watch`: Runs all the tests and watches for changes. Vitest
automatically only runs the tests that are affected by the code you've
changed.

We don't have a very strict policy about testing coverage, but we do try to
keep things tested to both avoid regressions and to make sure that the code is
working as expected.

A good rule of thumb is that if you need to simulate use
cases to just check whether a specific portion of code works, you should
probably have that split into a function with a matching unit test.

29 changes: 29 additions & 0 deletions apps/docs/contributing/development-workflow/3-linting.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: 'Linting'
sidebarTitle: '3. Linting'
'og:image': 'https://react.email/static/covers/react-email.png'
description: 'How we do linting and how you should run it'
---

We use [eslint](https://eslint.org/) for linting, and we have a private unpublished package
called <br/>`eslint-config-custom` that we share across packages and apps. This package is not meant to be
used outside the repository and is not published to npm.

For each type of project we have a different configuration to extend and use from the shared configuration,
they are all based on the [Vercel Engineering Style Guide](https://github.com/vercel/style-guide).
If you want to run linting check on a specific package they all have a `lint` script that you can run
with

```bash inside of any package, or in the react-email project root
pnpm lint
```

We also use [prettier](https://prettier.io/) for formatting, and we have just one configuration
for all the projects on the root of the repo, if you want to use it you can just run:

```bash react-email project root
pnpm format
```

Both the linting and formatting are ensured by our GitHub CI so make sure that you have your linting
and formatting right before you get to opening a PR or asking for a review on it.
37 changes: 37 additions & 0 deletions apps/docs/contributing/development-workflow/4-building.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
title: "Building"
sidebarTitle: "4. Building"
"og:image": "https://react.email/static/covers/react-email.png"
description: "How we build each package before publishing"
---

What we currently use, for the most part, is the awesome
[tsup](https://github.com/egoist/tsup). The only exception for this is the
`@react-email/tailwind` package which currently uses
[vite](https://vitejs.dev/) due to a few issues with `tsup` and `tailwindcss`'s
bundling. If you want to build a package you can just run:

```bash package/* (ex: package/render)
pnpm build
```

This will literally run `tsup` with a few settings we have for it. Generally
they are just<br/> `src/index.ts --format esm,cjs --dts --external react` which
generates both an [ESM](https://nodejs.org/api/esm.html) and
[CJS](https://nodejs.org/docs/latest/api/modules.html) versions of the package
and the type definitions that were exported from `src/index.ts`, which is the
entry point. `--external react` here ensures that `react` is not bundled in
which can cause many issues.

### Why build before publishing?

Currently, we do building for most of the packages. This is important for a few
key reasons that improve the usability of each package:

1. All the exported types can be imported from the same place the JavaScript is
imported
2. We have proper
[CommonJS](https://nodejs.org/docs/latest/api/modules.html#modules-commonjs-modules)
and [ES Modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules)
support
3. Code that isn't exported is not published nor downloaded
Loading
Loading