Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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/compose-react-email-unformatted-html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/editor": minor
---

expose the unformatted (non-prettified) HTML from `composeReactEmail` as a new `unformattedHtml` field on the result. The existing `html` field is unchanged and still Prettier-formatted. Consumers that persist or send the email should prefer `unformattedHtml`, since `pretty()` indentation can inflate the byte size by 5–10× on deeply-nested table layouts (e.g. exports from Stripo or Mailchimp) and pushes the output past Gmail's 102 KB clipping threshold.
29 changes: 29 additions & 0 deletions packages/editor/src/core/serializer/compose-react-email.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -496,3 +496,32 @@ describe('Button and image reset styles', () => {
expect(result.html).toContain('test image');
});
});

it('exposes unformattedHtml alongside the prettified html and text', async () => {
const content = docWithGlobalContent([
{
type: 'paragraph',
content: [{ type: 'text', text: 'Hello world' }],
},
]);

const ed = createEditorWithContent(content, [EmailTheming]);
const result = await composeReactEmail({ editor: ed });

// Field is present and non-empty.
expect(typeof result.unformattedHtml).toBe('string');
expect(result.unformattedHtml.length).toBeGreaterThan(0);

// Same body content as the pretty version (both contain the text).
expect(result.unformattedHtml).toContain('Hello world');

// No Prettier indentation artifacts: no inter-tag whitespace runs.
expect(result.unformattedHtml).not.toMatch(/>\s+</);

// The pretty version, by contrast, does indent between tags.
expect(result.html).toMatch(/>\s+</);

// And the unformatted version is shorter precisely because indentation
// is the only difference.
expect(result.unformattedHtml.length).toBeLessThan(result.html.length);
});
12 changes: 11 additions & 1 deletion packages/editor/src/core/serializer/compose-react-email.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,18 @@ function sortMarksBySchema(
}

interface ComposeReactEmailResult {
/** Prettier-formatted HTML, suitable for displaying in a source-code view. */
html: string;
/** Plain-text version of the email body. */
text: string;
/**
* Unformatted HTML as produced by `render()` before `pretty()` runs.
* Use this when persisting or sending the email — Prettier indentation
* can inflate the byte size by 5–10× on deeply-nested table layouts
* (e.g. exports from Stripo, Mailchimp), and adds nothing for clients
* that parse HTML to render it.
*/
unformattedHtml: string;
}

export const composeReactEmail = async ({
Expand Down Expand Up @@ -150,5 +160,5 @@ export const composeReactEmail = async ({
toPlainText(unformattedHtml),
]);

return { html: prettyHtml, text };
return { html: prettyHtml, text, unformattedHtml };
};
Loading