Skip to content

feat(render): react-server export with experimental use of react-markup #2270

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

Draft
wants to merge 48 commits into
base: canary
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
7258de5
feat(tailwind): extract pseudo classes to stylesheet (#1864)
Sjoertjuh Feb 26, 2025
9331c9b
fix(tailwind): Infinite loop during sanitization
gabrielmfern Feb 27, 2025
3ade363
chore(tailwind): Improve code for running Tailwind integration test (…
gabrielmfern Feb 27, 2025
b3d2a65
chore: Enter pre-release
gabrielmfern Apr 8, 2025
6fbb26f
chore(root): Version packages (canary) (#2064)
github-actions[bot] Apr 8, 2025
8f8bc7e
fix(tailwind): linter (#2021)
bukinoshita Apr 9, 2025
077e19f
chore(root): Version packages (canary) (#2087)
github-actions[bot] Apr 14, 2025
a939962
chore(root): Version packages (canary) (#2088)
github-actions[bot] Apr 15, 2025
86dcbb5
chore(root): Version packages (canary) (#2090)
github-actions[bot] Apr 15, 2025
97f54fe
chore(root): Version packages (canary) (#2092)
github-actions[bot] Apr 16, 2025
0924465
chore(root): Version packages (canary) (#2096)
github-actions[bot] Apr 16, 2025
1493491
chore(root): Version packages (canary) (#2098)
github-actions[bot] Apr 16, 2025
8545822
chore(root): Version packages (canary) (#2175)
github-actions[bot] Apr 21, 2025
b530f1f
chore: name release canary workflow according to Resend's standard (#…
bukinoshita May 5, 2025
34639ac
chore(deps): update changesets/action digest to 5f15b43 (#2198)
renovate[bot] May 5, 2025
540ff3a
chore(deps): update buildjet/cache digest to 9347ea1 (#2197)
renovate[bot] May 5, 2025
eec8d13
chore(deps): update dependency vite to v6.3.4 [security] (#2196)
renovate[bot] May 5, 2025
b95adf1
chore(root): Version packages (canary) (#2184)
github-actions[bot] May 5, 2025
2b23caa
Revert "chore(deps): update changesets/action digest to 5f15b43 (#2198)"
gabrielmfern May 5, 2025
a73ebe0
chore(react-email): Pre-render email templates on hover (#2187)
gabrielmfern May 5, 2025
d763b21
fix(ci): Discrepancy between Preview Reelase workflow and tests (#2219)
gabrielmfern May 6, 2025
25b2dfe
chore(root): Add `minor` changeset for @react-email/components
gabrielmfern May 6, 2025
d8ee381
fix(render): reactDOMServer import on browser and some bundlers (#2221)
MendyLanda May 7, 2025
add2429
chore(react-email): 'email: not found' error during CI after caching …
gabrielmfern May 7, 2025
c28b9ab
chore(ci): Remove `push` from trigger for preview releases
gabrielmfern May 7, 2025
e206a71
feat(react-email): Polished way of ensuring `email` binary is availab…
gabrielmfern May 7, 2025
6d18b5e
chore(root): Version packages (canary) (#2217)
github-actions[bot] May 7, 2025
0d357ff
chore(root): Version packages (canary) (#2233)
github-actions[bot] May 12, 2025
9892b93
feat(button): respect the user's order of padding properties (#2234)
gabrielmfern May 12, 2025
8d34ee9
feat(react-email): TypeScript's path aliases support for hot reloadin…
gabrielmfern May 12, 2025
6b2b7f9
chore(root): Add changesets
gabrielmfern May 12, 2025
47d67ab
chore(root): Improve changeset for components
gabrielmfern May 12, 2025
8b786aa
chore(root): Version packages (canary) (#2236)
github-actions[bot] May 12, 2025
e028cab
chore(changeset): Update initial versions after cherry-picked changes
gabrielmfern May 13, 2025
d0e8b1f
fix(react-email): prettier errors causing NextJS serialization error …
gabrielmfern May 16, 2025
6a2f35b
chore(root): Version packages (canary) (#2238)
github-actions[bot] May 16, 2025
3396240
chore: Update initial version for react-email
gabrielmfern May 16, 2025
f7e553f
chore: Update initial versions for pre.json
gabrielmfern May 20, 2025
ed2f46a
feat: Separate preview server from `react-email` (#2182)
gabrielmfern May 20, 2025
6b3a109
chore(root): Version packages (canary) (#2255)
github-actions[bot] May 20, 2025
ec62a29
FIX: fix(types): correct typo in SupportEntryCategory type (#2260)
PedroMarianoAlmeida May 22, 2025
a3ac2d3
docs(readme): split build and run instructions for clarity (#2261)
PedroMarianoAlmeida May 26, 2025
4cb4cd9
chore(root): Update biome to beta.5 (#2264)
gabrielmfern May 26, 2025
efb4db2
fix(preview-server): `<svg>` not being flagged by compatibility check…
PedroMarianoAlmeida May 27, 2025
1cce50e
chore(root): Version packages (canary) (#2266)
github-actions[bot] May 27, 2025
e22cc83
fix(render): Browser version including errors in the output instead o…
gabrielmfern May 28, 2025
4477b93
chore(root): Version packages (canary) (#2269)
github-actions[bot] May 28, 2025
dc5c519
and react-server export using react-markup
gabrielmfern May 28, 2025
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
5 changes: 5 additions & 0 deletions .changeset/afraid-sides-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/preview-server": patch
---

fix `<svg>` not being flagged as incompatible
5 changes: 5 additions & 0 deletions .changeset/crazy-seas-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/components": minor
---

Update `@react-email/[email protected]`
5 changes: 5 additions & 0 deletions .changeset/deep-clowns-bet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/render": patch
---

fix browser version including errors in the output instead of throwing them
5 changes: 5 additions & 0 deletions .changeset/great-parrots-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/tailwind": minor
---

Extract tailwind pseudo classes to stylesheet
5 changes: 5 additions & 0 deletions .changeset/mighty-pigs-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-email": patch
---

Add support for hot reloading with tsconfig path aliases
49 changes: 49 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"mode": "pre",
"tag": "canary",
"initialVersions": {
"demo": "0.0.0",
"docs": "0.0.0",
"web": "0.0.0",
"@benchmarks/preview-server": "0.0.0",
"@benchmarks/tailwind-component": "0.0.0",
"@react-email/body": "0.0.11",
"@react-email/button": "0.0.19",
"@react-email/code-block": "0.0.13",
"@react-email/code-inline": "0.0.5",
"@react-email/column": "0.0.13",
"@react-email/components": "0.0.41",
"@react-email/container": "0.0.15",
"create-email": "1.2.1",
"react-email-starter": "1.0.7",
"@react-email/font": "0.0.9",
"@react-email/head": "0.0.12",
"@react-email/heading": "0.0.15",
"@react-email/hr": "0.0.11",
"@react-email/html": "0.0.11",
"@react-email/img": "0.0.11",
"@react-email/link": "0.0.12",
"@react-email/markdown": "0.0.15",
"@react-email/preview": "0.0.13",
"react-email": "4.0.15",
"@react-email/render": "1.1.2",
"@react-email/row": "0.0.12",
"@react-email/section": "0.0.16",
"@react-email/tailwind": "1.0.5",
"@react-email/text": "0.1.4",
"tsconfig": "0.0.0",
"@react-email/preview-server": "1.0.0-canary.0"
},
"changesets": [
"afraid-sides-agree",
"crazy-seas-eat",
"deep-clowns-bet",
"great-parrots-yell",
"mighty-pigs-add",
"puny-chicken-argue",
"stupid-ghosts-decide",
"tasty-swans-taste",
"tidy-geese-cross",
"tiny-rice-give"
]
}
5 changes: 5 additions & 0 deletions .changeset/puny-chicken-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-email": minor
---

use a separate package for storing the preview server (@react-email/preview-server)
5 changes: 5 additions & 0 deletions .changeset/stupid-ghosts-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-email": patch
---

Fix prettier errors causing NextJS serialization error
5 changes: 5 additions & 0 deletions .changeset/tasty-swans-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/components": minor
---

Updated @react-email/[email protected]
5 changes: 5 additions & 0 deletions .changeset/tidy-geese-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-email": patch
---

Pre-render email templates on hover
5 changes: 5 additions & 0 deletions .changeset/tiny-rice-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/button": minor
---

respect the order in which padding properties are defined
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
- name: pnpm Cache
id: pnpm-cache
uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4
uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372
with:
path: |
~/.pnpm-store
Expand Down
14 changes: 3 additions & 11 deletions .github/workflows/preview-release.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
name: Preview Release
on:
pull_request:
push:
branches:
- main
- canary
permissions:
contents: read
pull-requests: write
Expand All @@ -15,20 +11,16 @@ jobs:
permissions:
contents: write
pull-requests: write
container:
image: node:22
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: pnpm setup
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
- name: pnpm Cache
id: pnpm-cache
uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4
uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372
with:
path: |
~/.pnpm-store
Expand Down
13 changes: 2 additions & 11 deletions .github/workflows/release-canary.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
name: rsnd

name: Release Canary
on:
push:
branches:
- canary

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
release:
name: release canary
Expand All @@ -19,21 +16,18 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Enable Corepack
id: pnpm-setup
run: |
corepack enable
corepack prepare [email protected] --activate
pnpm config set script-shell "/usr/bin/bash"

- name: pnpm Cache
uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4
uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372
with:
path: |
~/.pnpm-store
Expand All @@ -42,16 +36,13 @@ jobs:
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-

- name: Install packages
if: steps.pnpm-cache.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile

- name: Enter prerelease mode
# This step errors if it is already in prerelease mode
continue-on-error: true
run: pnpm canary:enter

- name: Create "Version packages" PR or publish release
uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
- name: pnpm Cache
id: pnpm-cache
uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4
uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372
with:
path: |
~/.pnpm-store
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:

- name: pnpm Cache
id: pnpm-cache
uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4
uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372
with:
path: |
~/.pnpm-store
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,13 @@ All components were tested using the most popular email clients.
pnpm install
```

#### Build and run packages
#### Build

```sh
pnpm build
```

#### Run packages

```sh
pnpm dev
Expand Down
5 changes: 3 additions & 2 deletions apps/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"scripts": {
"build": "email build",
"build": "pnpm install --frozen-lockfile && email build",
"dev": "email dev",
"start": "email start",
"export": "email export"
Expand All @@ -15,7 +15,8 @@
"react-email": "workspace:*"
},
"devDependencies": {
"next": "15.3.1",
"@react-email/preview-server": "workspace:*",
"next": "^15.2.4",
"@types/react": "^19",
"@types/react-dom": "^19",
"tsx": "4.19.3"
Expand Down
2 changes: 1 addition & 1 deletion apps/web/components/customer-reviews/tailwind.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export const component = (
</Text>
<Button
href="#"
className="mt-[26px] mb-[24px] inline-block w-full rounded-[8px] bg-indigo-600 p-3 text-center box-border font-semibold text-white"
className="mt-[26px] mb-[24px] inline-block w-full rounded-[8px] bg-indigo-600 p-[12px] text-center box-border font-semibold text-white"
>
Write a review
</Button>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/template.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use client';

import classNames from 'classnames';
import Image from 'next/image';
import type { ImageLoader } from 'next/image';
import Image from 'next/image';
import Link from 'next/link';
import * as React from 'react';
import { Heading } from './heading';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const parsePointingTableRows = (response: string) => {
const responseFromTableStart = response.slice(
tableStartMatch.index + tableStartMatch[0].length,
);
let currentRow: Row | undefined = undefined;
let currentRow: Row | undefined;
for (const line of responseFromTableStart.split(/\r\n|\n|\r/)) {
if (line.trim().length === 0) break;

Expand Down
7 changes: 4 additions & 3 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.0-beta.1/schema.json",
"$schema": "https://biomejs.dev/schemas/2.0.0-beta.5/schema.json",
"assist": {
"actions": {
"source": {
Expand Down Expand Up @@ -31,7 +31,6 @@
"noCommaOperator": "error",
"useNodejsImportProtocol": "error",
"useAsConstAssertion": "error",
"useNumericLiterals": "error",
"useEnumInitializers": "error",
"useSelfClosingElements": "error",
"useConst": "error",
Expand All @@ -54,6 +53,7 @@
"noDelete": "off"
},
"a11y": {
"noStaticElementInteractions": "off",
"noSvgWithoutTitle": "off",
"noAutofocus": "off"
},
Expand All @@ -67,6 +67,7 @@
"useSortedClasses": "off"
},
"complexity": {
"useNumericLiterals": "error",
"noUselessFragments": "off",
"noForEach": "off"
},
Expand All @@ -87,7 +88,7 @@
"!**/pnpm-lock.yaml",
"!**/.next",
"!**/public",
"!packages/react-email/src/actions/email-validation/caniemail-data.ts",
"!packages/preview-server/src/actions/email-validation/caniemail-data.ts",
"!**/.react-email/**/*",
"!**/node_modules/**/*",
"!**/*.d.ts",
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"test:watch": "turbo run test:watch"
},
"devDependencies": {
"@biomejs/biome": "2.0.0-beta.1",
"@biomejs/biome": "2.0.0-beta.5",
"@changesets/cli": "2.29.2",
"@types/node": "22.14.1",
"@types/react": "19.0.1",
Expand All @@ -25,7 +25,7 @@
"tsconfig": "workspace:*",
"tsup": "8.4.0",
"turbo": "2.5.0",
"vite": "6.3.2",
"vite": "6.3.4",
"vitest": "3.1.1"
},
"pnpm": {
Expand Down
6 changes: 6 additions & 0 deletions packages/button/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @react-email/button

## 0.1.0-canary.0

### Minor Changes

- 11c4600: respect the order in which padding properties are defined

## 0.0.19

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/button/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@react-email/button",
"version": "0.0.19",
"version": "0.1.0-canary.0",
"description": "A link that is styled to look like a button",
"sideEffects": false,
"main": "./dist/index.js",
Expand Down
6 changes: 3 additions & 3 deletions packages/button/src/__snapshots__/button.spec.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`<Button> component > renders correctly with padding values from style prop 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><a href="https://example.com" style="line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:12px 20px 12px 20px" target="_blank"><span><!--[if mso]><i style="mso-font-width:500%;mso-text-raise:18" hidden>&#8202;&#8202;</i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px"></span><span><!--[if mso]><i style="mso-font-width:500%" hidden>&#8202;&#8202;&#8203;</i><![endif]--></span></a><!--/$-->"`;
exports[`<Button> component > renders correctly with padding values from style prop 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><a href="https://example.com" style="line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:12px 20px;padding-top:12px;padding-right:20px;padding-bottom:12px;padding-left:20px" target="_blank"><span><!--[if mso]><i style="mso-font-width:500%;mso-text-raise:18" hidden>&#8202;&#8202;</i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px"></span><span><!--[if mso]><i style="mso-font-width:500%" hidden>&#8202;&#8202;&#8203;</i><![endif]--></span></a><!--/$-->"`;

exports[`<Button> component > renders the <Button> component with no padding value 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><a href="https://example.com" style="line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:0px 0px 0px 0px" target="_blank"><span><!--[if mso]><i style="mso-font-width:0%;mso-text-raise:0" hidden></i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:0"></span><span><!--[if mso]><i style="mso-font-width:0%" hidden>&#8203;</i><![endif]--></span></a><!--/$-->"`;
exports[`<Button> component > renders the <Button> component with no padding value 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><a href="https://example.com" style="line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px" target="_blank"><span><!--[if mso]><i style="mso-font-width:0%;mso-text-raise:0" hidden></i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px"></span><span><!--[if mso]><i style="mso-font-width:0%" hidden>&#8203;</i><![endif]--></span></a><!--/$-->"`;

exports[`<Button> component > should allow users to overwrite style props 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><a style="line-height:150%;text-decoration:underline red;display:block;max-width:50%;mso-padding-alt:0px;padding:0px 0px 0px 0px" target="_blank"><span><!--[if mso]><i style="mso-font-width:0%;mso-text-raise:0" hidden></i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:0"></span><span><!--[if mso]><i style="mso-font-width:0%" hidden>&#8203;</i><![endif]--></span></a><!--/$-->"`;
exports[`<Button> component > should allow users to overwrite style props 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><a style="line-height:150%;text-decoration:underline red;display:block;max-width:50%;mso-padding-alt:0px" target="_blank"><span><!--[if mso]><i style="mso-font-width:0%;mso-text-raise:0" hidden></i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px"></span><span><!--[if mso]><i style="mso-font-width:0%" hidden>&#8203;</i><![endif]--></span></a><!--/$-->"`;
Loading
Loading