Skip to content

Commit f5f35f1

Browse files
fix(render): prevent react hydration markers on large emails (#2383)
Co-authored-by: Gabriel Miranda <[email protected]>
1 parent 9e52a9d commit f5f35f1

File tree

9 files changed

+112
-51
lines changed

9 files changed

+112
-51
lines changed

.changeset/ninety-lions-train.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-email/render": patch
3+
---
4+
5+
fix hydration markers on React canary/Next.js latest when rendering large email templates

packages/render/src/browser/__snapshots__/render-web.spec.tsx.snap

Lines changed: 2 additions & 50 deletions
Large diffs are not rendered by default.

packages/render/src/browser/render-web.spec.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,36 @@ describe('render on the browser environment', () => {
146146
const element = createElement(undefined);
147147
await expect(render(element)).rejects.toThrowErrorMatchingSnapshot();
148148
});
149+
150+
/**
151+
* Create a large email that would trigger React's streaming optimization
152+
* if progressiveChunkSize wasn't set to Infinity
153+
*
154+
* @see https://github.com/resend/react-email/issues/2353
155+
*/
156+
it('should render large emails without hydration markers', async () => {
157+
const LargeEmailTemplate = () => {
158+
const largeContent = Array(100)
159+
.fill(null)
160+
.map((_, i) => (
161+
<p key={i}>
162+
This is paragraph {i} with some content to make the email larger.
163+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
164+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
165+
ad minim veniam, quis nostrud exercitation ullamco laboris.
166+
</p>
167+
));
168+
169+
return (
170+
<div>
171+
<h1>Large Email Test</h1>
172+
{largeContent}
173+
</div>
174+
);
175+
};
176+
177+
const actualOutput = await render(<LargeEmailTemplate />);
178+
179+
expect(actualOutput).toMatchSnapshot();
180+
});
149181
});

packages/render/src/browser/render.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const render = async (node: React.ReactNode, options?: Options) => {
5151
onError(error: unknown) {
5252
reject(error);
5353
},
54+
progressiveChunkSize: Number.POSITIVE_INFINITY,
5455
})
5556
.then(readStream)
5657
.then(resolve)

packages/render/src/node/__snapshots__/render-edge.spec.tsx.snap

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

packages/render/src/node/__snapshots__/render-node.spec.tsx.snap

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

packages/render/src/node/render-edge.spec.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,36 @@ describe('render on the edge', () => {
107107
`"THIS SHOULD BE RENDERED IN PLAIN TEXT"`,
108108
);
109109
});
110+
111+
/**
112+
* Create a large email that would trigger React's streaming optimization
113+
* if progressiveChunkSize wasn't set to Infinity
114+
*
115+
* @see https://github.com/resend/react-email/issues/2353
116+
*/
117+
it('should render large emails without hydration markers', async () => {
118+
const LargeEmailTemplate = () => {
119+
const largeContent = Array(100)
120+
.fill(null)
121+
.map((_, i) => (
122+
<p key={i}>
123+
This is paragraph {i} with some content to make the email larger.
124+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
125+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
126+
ad minim veniam, quis nostrud exercitation ullamco laboris.
127+
</p>
128+
));
129+
130+
return (
131+
<div>
132+
<h1>Large Email Test</h1>
133+
{largeContent}
134+
</div>
135+
);
136+
};
137+
138+
const actualOutput = await render(<LargeEmailTemplate />);
139+
140+
expect(actualOutput).toMatchSnapshot();
141+
});
110142
});

packages/render/src/node/render-node.spec.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,36 @@ describe('render on node environments', () => {
133133
`"THIS SHOULD BE RENDERED IN PLAIN TEXT"`,
134134
);
135135
});
136+
137+
/**
138+
* Create a large email that would trigger React's streaming optimization
139+
* if progressiveChunkSize wasn't set to Infinity
140+
*
141+
* @see https://github.com/resend/react-email/issues/2353
142+
*/
143+
it('should render large emails without hydration markers', async () => {
144+
const LargeEmailTemplate = () => {
145+
const largeContent = Array(100)
146+
.fill(null)
147+
.map((_, i) => (
148+
<p key={i}>
149+
This is paragraph {i} with some content to make the email larger.
150+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
151+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
152+
ad minim veniam, quis nostrud exercitation ullamco laboris.
153+
</p>
154+
));
155+
156+
return (
157+
<div>
158+
<h1>Large Email Test</h1>
159+
{largeContent}
160+
</div>
161+
);
162+
};
163+
164+
const actualOutput = await render(<LargeEmailTemplate />);
165+
166+
expect(actualOutput).toMatchSnapshot();
167+
});
136168
});

packages/render/src/node/render.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ export const render = async (node: React.ReactNode, options?: Options) => {
1515
let html!: string;
1616
if (Object.hasOwn(reactDOMServer, 'renderToReadableStream')) {
1717
html = await readStream(
18-
await reactDOMServer.renderToReadableStream(suspendedElement),
18+
await reactDOMServer.renderToReadableStream(suspendedElement, {
19+
progressiveChunkSize: Number.POSITIVE_INFINITY,
20+
}),
1921
);
2022
} else {
2123
await new Promise<void>((resolve, reject) => {
@@ -27,6 +29,7 @@ export const render = async (node: React.ReactNode, options?: Options) => {
2729
onError(error) {
2830
reject(error as Error);
2931
},
32+
progressiveChunkSize: Number.POSITIVE_INFINITY,
3033
});
3134
});
3235
}

0 commit comments

Comments
 (0)