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

[Fax] Publish experimental_renderToHTML #30690

Merged
merged 4 commits into from
Aug 15, 2024
Merged
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
6 changes: 5 additions & 1 deletion packages/react-markup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ npm install react react-markup
## Usage

```js
import { renderToHTML } from 'react-markup';
import { experimental_renderToHTML as renderToHTML } from 'react-markup';
import EmailTemplate from './my-email-template-component.js'

async function action(email, name) {
Expand All @@ -30,3 +30,7 @@ Note that this is an async function that needs to be awaited - unlike the legacy
### `react-markup`

See https://react.dev/reference/react-markup

## Thanks

The React team thanks [Nikolai Mavrenkov](https://www.koluch.ru/) for donating the `react-markup` package name.
3 changes: 1 addition & 2 deletions packages/react-markup/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"name": "react-markup",
"version": "19.0.0",
"private": true,
"description": "React package generating embedded HTML markup such as e-mails using Server Components.",
"description": "React package generating embedded markup such as e-mails with support for Server Components.",
"main": "index.js",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-markup/src/ReactMarkupClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type MarkupOptions = {
onError?: (error: mixed, errorInfo: ErrorInfo) => ?string,
};

export function renderToHTML(
export function experimental_renderToHTML(
children: ReactNodeList,
options?: MarkupOptions,
): Promise<string> {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-markup/src/ReactMarkupServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function noServerCallOrFormAction() {
);
}

export function renderToHTML(
export function experimental_renderToHTML(
children: ReactMarkupNodeList,
options?: MarkupOptions,
): Promise<string> {
Expand Down
30 changes: 18 additions & 12 deletions packages/react-markup/src/__tests__/ReactMarkupClient-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ if (!__EXPERIMENTAL__) {
return <div>hello world</div>;
}

const html = await ReactMarkup.renderToHTML(<Component />);
const html = await ReactMarkup.experimental_renderToHTML(<Component />);
expect(html).toBe('<div>hello world</div>');
});

Expand All @@ -52,14 +52,14 @@ if (!__EXPERIMENTAL__) {
return <div>{'hello '.repeat(200)}world</div>;
}

const html = await ReactMarkup.renderToHTML(
const html = await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
expect(html).toBe('<div>' + ('hello '.repeat(200) + 'world') + '</div>');
});

it('should prefix html tags with a doctype', async () => {
const html = await ReactMarkup.renderToHTML(
const html = await ReactMarkup.experimental_renderToHTML(
<html>
<body>hello</body>
</html>,
Expand All @@ -76,8 +76,10 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(<Component />);
}).rejects.toThrow();
await ReactMarkup.experimental_renderToHTML(<Component />);
}).rejects.toThrow(
'Cannot use state or effect Hooks in renderToHTML because this component will never be hydrated.',
);
});

it('should error on refs passed to host components', async () => {
Expand All @@ -87,8 +89,10 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(<Component />);
}).rejects.toThrow();
await ReactMarkup.experimental_renderToHTML(<Component />);
}).rejects.toThrow(
'Cannot pass ref in renderToHTML because they will never be hydrated.',
);
});

it('should error on callbacks passed to event handlers', async () => {
Expand All @@ -100,8 +104,10 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(<Component />);
}).rejects.toThrow();
await ReactMarkup.experimental_renderToHTML(<Component />);
}).rejects.toThrow(
'Cannot pass event handlers (onClick) in renderToHTML because the HTML will never be hydrated so they can never get called.',
);
});

it('supports the useId Hook', async () => {
Expand Down Expand Up @@ -142,7 +148,7 @@ if (!__EXPERIMENTAL__) {
);
}

const html = await ReactMarkup.renderToHTML(<Component />);
const html = await ReactMarkup.experimental_renderToHTML(<Component />);
const container = document.createElement('div');
container.innerHTML = html;

Expand Down Expand Up @@ -176,7 +182,7 @@ if (!__EXPERIMENTAL__) {
);
}

const html = await ReactMarkup.renderToHTML(<Component />);
const html = await ReactMarkup.experimental_renderToHTML(<Component />);
expect(html).toBe('<div>01</div>');
});

Expand All @@ -199,7 +205,7 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(
await ReactMarkup.experimental_renderToHTML(
<div>
<Foo />
</div>,
Expand Down
43 changes: 30 additions & 13 deletions packages/react-markup/src/__tests__/ReactMarkupServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ if (!__EXPERIMENTAL__) {
return React.createElement('div', null, 'hello world');
}

const html = await ReactMarkup.renderToHTML(
const html = await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
expect(html).toBe('<div>hello world</div>');
Expand All @@ -76,15 +76,14 @@ if (!__EXPERIMENTAL__) {
return React.createElement('div', null, 'hello '.repeat(200) + 'world');
}

const html = await ReactMarkup.renderToHTML(
const html = await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
expect(html).toBe('<div>' + ('hello '.repeat(200) + 'world') + '</div>');
});

it('should prefix html tags with a doctype', async () => {
const html = await ReactMarkup.renderToHTML(
// We can't use JSX because that's client-JSX in our tests.
const html = await ReactMarkup.experimental_renderToHTML(
React.createElement(
'html',
null,
Expand All @@ -104,8 +103,10 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(React.createElement(Component));
}).rejects.toThrow();
await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
}).rejects.toThrow('React.useState is not a function');
});

it('should error on refs passed to host components', async () => {
Expand All @@ -116,8 +117,12 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(React.createElement(Component));
}).rejects.toThrow();
await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
}).rejects.toThrow(
'Refs cannot be used in Server Components, nor passed to Client Components.',
);
});

it('should error on callbacks passed to event handlers', async () => {
Expand All @@ -130,8 +135,20 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(React.createElement(Component));
}).rejects.toThrow();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test would've passed without renaming so I added the exact message we expect.

await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
}).rejects.toThrowError(
__DEV__
? `Event handlers cannot be passed to Client Component props.\n` +
' <div onClick={function onClick}>\n' +
' ^^^^^^^^^^^^^^^^^^\n' +
'If you need interactivity, consider converting part of this to a Client Component.'
: `Event handlers cannot be passed to Client Component props.\n` +
' {onClick: function onClick}\n' +
' ^^^^^^^^^^^^^^^^\n' +
'If you need interactivity, consider converting part of this to a Client Component.',
);
});

it('supports the useId Hook', async () => {
Expand Down Expand Up @@ -173,7 +190,7 @@ if (!__EXPERIMENTAL__) {
);
}

const html = await ReactMarkup.renderToHTML(
const html = await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
const container = document.createElement('div');
Expand Down Expand Up @@ -204,7 +221,7 @@ if (!__EXPERIMENTAL__) {
return React.createElement('div', null, a, b);
}

const html = await ReactMarkup.renderToHTML(
const html = await ReactMarkup.experimental_renderToHTML(
React.createElement(Component),
);
expect(html).toBe('<div>00</div>');
Expand All @@ -225,7 +242,7 @@ if (!__EXPERIMENTAL__) {
}

await expect(async () => {
await ReactMarkup.renderToHTML(
await ReactMarkup.experimental_renderToHTML(
React.createElement('div', null, React.createElement(Foo)),
{
onError(error, errorInfo) {
Expand Down
Loading