@samitouri / QOS-React / commits / cea13feb34

Publish `experimental_renderToHTML` (#30690)

Sebastian Silbermann committed Aug 15, 2024 at 08:50 UTC cea13feb3449317d8570ba17603747497037d264
6 files changed +56 -30
packages/react-markup/README.md
+5 -1
@@ -11,7 +11,7 @@ npm install react react-markup
11 ## Usage
12
13 ```js
14 -import { renderToHTML } from 'react-markup';
14 +import { experimental_renderToHTML as renderToHTML } from 'react-markup';
15 import EmailTemplate from './my-email-template-component.js'
16
17 async function action(email, name) {
@@ -30,3 +30,7 @@ Note that this is an async function that needs to be awaited - unlike the legacy
30 ### `react-markup`
31
32 See https://react.dev/reference/react-markup
33 +
34 +## Thanks
35 +
36 +The React team thanks [Nikolai Mavrenkov](https://www.koluch.ru/) for donating the `react-markup` package name.
packages/react-markup/package.json
+1 -2
@@ -1,8 +1,7 @@
1 {
2 "name": "react-markup",
3 "version": "19.0.0",
4 - "private": true,
5 - "description": "React package generating embedded HTML markup such as e-mails using Server Components.",
4 + "description": "React package generating embedded markup such as e-mails with support for Server Components.",
5 "main": "index.js",
6 "repository": {
7 "type": "git",
packages/react-markup/src/ReactMarkupClient.js
+1 -1
@@ -31,7 +31,7 @@ type MarkupOptions = {
31 onError?: (error: mixed, errorInfo: ErrorInfo) => ?string,
32 };
33
34 -export function renderToHTML(
34 +export function experimental_renderToHTML(
35 children: ReactNodeList,
36 options?: MarkupOptions,
37 ): Promise<string> {
packages/react-markup/src/ReactMarkupServer.js
+1 -1
@@ -75,7 +75,7 @@ function noServerCallOrFormAction() {
75 );
76 }
77
78 -export function renderToHTML(
78 +export function experimental_renderToHTML(
79 children: ReactMarkupNodeList,
80 options?: MarkupOptions,
81 ): Promise<string> {
packages/react-markup/src/__tests__/ReactMarkupClient-test.js
+18 -12
@@ -43,7 +43,7 @@ if (!__EXPERIMENTAL__) {
43 return <div>hello world</div>;
44 }
45
46 - const html = await ReactMarkup.renderToHTML(<Component />);
46 + const html = await ReactMarkup.experimental_renderToHTML(<Component />);
47 expect(html).toBe('<div>hello world</div>');
48 });
49
@@ -52,14 +52,14 @@ if (!__EXPERIMENTAL__) {
52 return <div>{'hello '.repeat(200)}world</div>;
53 }
54
55 - const html = await ReactMarkup.renderToHTML(
55 + const html = await ReactMarkup.experimental_renderToHTML(
56 React.createElement(Component),
57 );
58 expect(html).toBe('<div>' + ('hello '.repeat(200) + 'world') + '</div>');
59 });
60
61 it('should prefix html tags with a doctype', async () => {
62 - const html = await ReactMarkup.renderToHTML(
62 + const html = await ReactMarkup.experimental_renderToHTML(
63 <html>
64 <body>hello</body>
65 </html>,
@@ -76,8 +76,10 @@ if (!__EXPERIMENTAL__) {
76 }
77
78 await expect(async () => {
79 - await ReactMarkup.renderToHTML(<Component />);
80 - }).rejects.toThrow();
79 + await ReactMarkup.experimental_renderToHTML(<Component />);
80 + }).rejects.toThrow(
81 + 'Cannot use state or effect Hooks in renderToHTML because this component will never be hydrated.',
82 + );
83 });
84
85 it('should error on refs passed to host components', async () => {
@@ -87,8 +89,10 @@ if (!__EXPERIMENTAL__) {
89 }
90
91 await expect(async () => {
90 - await ReactMarkup.renderToHTML(<Component />);
91 - }).rejects.toThrow();
92 + await ReactMarkup.experimental_renderToHTML(<Component />);
93 + }).rejects.toThrow(
94 + 'Cannot pass ref in renderToHTML because they will never be hydrated.',
95 + );
96 });
97
98 it('should error on callbacks passed to event handlers', async () => {
@@ -100,8 +104,10 @@ if (!__EXPERIMENTAL__) {
104 }
105
106 await expect(async () => {
103 - await ReactMarkup.renderToHTML(<Component />);
104 - }).rejects.toThrow();
107 + await ReactMarkup.experimental_renderToHTML(<Component />);
108 + }).rejects.toThrow(
109 + 'Cannot pass event handlers (onClick) in renderToHTML because the HTML will never be hydrated so they can never get called.',
110 + );
111 });
112
113 it('supports the useId Hook', async () => {
@@ -142,7 +148,7 @@ if (!__EXPERIMENTAL__) {
148 );
149 }
150
145 - const html = await ReactMarkup.renderToHTML(<Component />);
151 + const html = await ReactMarkup.experimental_renderToHTML(<Component />);
152 const container = document.createElement('div');
153 container.innerHTML = html;
154
@@ -176,7 +182,7 @@ if (!__EXPERIMENTAL__) {
182 );
183 }
184
179 - const html = await ReactMarkup.renderToHTML(<Component />);
185 + const html = await ReactMarkup.experimental_renderToHTML(<Component />);
186 expect(html).toBe('<div>01</div>');
187 });
188
@@ -199,7 +205,7 @@ if (!__EXPERIMENTAL__) {
205 }
206
207 await expect(async () => {
202 - await ReactMarkup.renderToHTML(
208 + await ReactMarkup.experimental_renderToHTML(
209 <div>
210 <Foo />
211 </div>,
packages/react-markup/src/__tests__/ReactMarkupServer-test.js
+30 -13
@@ -64,7 +64,7 @@ if (!__EXPERIMENTAL__) {
64 return React.createElement('div', null, 'hello world');
65 }
66
67 - const html = await ReactMarkup.renderToHTML(
67 + const html = await ReactMarkup.experimental_renderToHTML(
68 React.createElement(Component),
69 );
70 expect(html).toBe('<div>hello world</div>');
@@ -76,15 +76,14 @@ if (!__EXPERIMENTAL__) {
76 return React.createElement('div', null, 'hello '.repeat(200) + 'world');
77 }
78
79 - const html = await ReactMarkup.renderToHTML(
79 + const html = await ReactMarkup.experimental_renderToHTML(
80 React.createElement(Component),
81 );
82 expect(html).toBe('<div>' + ('hello '.repeat(200) + 'world') + '</div>');
83 });
84
85 it('should prefix html tags with a doctype', async () => {
86 - const html = await ReactMarkup.renderToHTML(
87 - // We can't use JSX because that's client-JSX in our tests.
86 + const html = await ReactMarkup.experimental_renderToHTML(
87 React.createElement(
88 'html',
89 null,
@@ -104,8 +103,10 @@ if (!__EXPERIMENTAL__) {
103 }
104
105 await expect(async () => {
107 - await ReactMarkup.renderToHTML(React.createElement(Component));
108 - }).rejects.toThrow();
106 + await ReactMarkup.experimental_renderToHTML(
107 + React.createElement(Component),
108 + );
109 + }).rejects.toThrow('React.useState is not a function');
110 });
111
112 it('should error on refs passed to host components', async () => {
@@ -116,8 +117,12 @@ if (!__EXPERIMENTAL__) {
117 }
118
119 await expect(async () => {
119 - await ReactMarkup.renderToHTML(React.createElement(Component));
120 - }).rejects.toThrow();
120 + await ReactMarkup.experimental_renderToHTML(
121 + React.createElement(Component),
122 + );
123 + }).rejects.toThrow(
124 + 'Refs cannot be used in Server Components, nor passed to Client Components.',
125 + );
126 });
127
128 it('should error on callbacks passed to event handlers', async () => {
@@ -130,8 +135,20 @@ if (!__EXPERIMENTAL__) {
135 }
136
137 await expect(async () => {
133 - await ReactMarkup.renderToHTML(React.createElement(Component));
134 - }).rejects.toThrow();
138 + await ReactMarkup.experimental_renderToHTML(
139 + React.createElement(Component),
140 + );
141 + }).rejects.toThrowError(
142 + __DEV__
143 + ? `Event handlers cannot be passed to Client Component props.\n` +
144 + ' <div onClick={function onClick}>\n' +
145 + ' ^^^^^^^^^^^^^^^^^^\n' +
146 + 'If you need interactivity, consider converting part of this to a Client Component.'
147 + : `Event handlers cannot be passed to Client Component props.\n` +
148 + ' {onClick: function onClick}\n' +
149 + ' ^^^^^^^^^^^^^^^^\n' +
150 + 'If you need interactivity, consider converting part of this to a Client Component.',
151 + );
152 });
153
154 it('supports the useId Hook', async () => {
@@ -173,7 +190,7 @@ if (!__EXPERIMENTAL__) {
190 );
191 }
192
176 - const html = await ReactMarkup.renderToHTML(
193 + const html = await ReactMarkup.experimental_renderToHTML(
194 React.createElement(Component),
195 );
196 const container = document.createElement('div');
@@ -204,7 +221,7 @@ if (!__EXPERIMENTAL__) {
221 return React.createElement('div', null, a, b);
222 }
223
207 - const html = await ReactMarkup.renderToHTML(
224 + const html = await ReactMarkup.experimental_renderToHTML(
225 React.createElement(Component),
226 );
227 expect(html).toBe('<div>00</div>');
@@ -225,7 +242,7 @@ if (!__EXPERIMENTAL__) {
242 }
243
244 await expect(async () => {
228 - await ReactMarkup.renderToHTML(
245 + await ReactMarkup.experimental_renderToHTML(
246 React.createElement('div', null, React.createElement(Foo)),
247 {
248 onError(error, errorInfo) {