Skip to content

Commit

Permalink
Address review comments
Browse files Browse the repository at this point in the history
- Use `collectResultSync()`
- Add jsdoc to exported functions
- `||` to `??`
- Some doc wording changes
  • Loading branch information
augustjk committed Apr 24, 2024
1 parent d7b5da5 commit fe8d064
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .changeset/polite-rice-stare.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
'@lit-labs/ssr-react': minor
---

The Node build of `@lit-labs/ssr-react/enable-lit-ssr.js` will now also monkey-patch `react/runtime-jsx` to include logic for deeply server-side rendering Lit components without modifying `jsxImportSource` in tsconfig.
The Node build of `@lit-labs/ssr-react/enable-lit-ssr.js` now also monkey-patches `react/runtime-jsx` to include logic for deeply server-rendering Lit components without modifying `jsxImportSource` in tsconfig.

The monkey-patching logic also adds a workaround for inconsistent es module interop behavior in tools like webpack which could lead to errors like `TypeError: Cannot set property createElement of [object Module] which has only a getter`.
2 changes: 1 addition & 1 deletion packages/labs/ssr-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ To get React SSR to deeply render Lit components, we'll need React JSX code to c

### Monkey patching React element creation (recommended)

This package provides the `@lit-labs/ssr-react/enable-lit-ssr.js` module which, when imported in a server environment, has the side-effect of monkey patching `React.createElement()` and runtime JSX functions to be enhanced to add the declarative shadow DOM output to registered custom elements. This can be imported at the entry point of the application before `React` is imported or any JSX containing Lit components is written.
This package provides the `@lit-labs/ssr-react/enable-lit-ssr.js` module which, when imported in a server environment, has the side-effect of monkey patching `React.createElement()` and runtime JSX functions to be enhanced to add the declarative shadow DOM output to registered custom elements. This can be imported at the entry point of the application before `React` is imported or any JSX containing Lit components is evaluated.

```js
// index.js
Expand Down
3 changes: 2 additions & 1 deletion packages/labs/ssr-react/src/lib/node/wrap-create-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import {isCustomElement} from '../utils.js';
import {renderCustomElement} from './render-custom-element.js';
import {collectResultSync} from '@lit-labs/ssr/lib/render-result.js';

import type {
createElement as ReactCreateElement,
Expand Down Expand Up @@ -37,7 +38,7 @@ export function wrapCreateElement(
const templateShadowRoot = originalCreateElement('template', {
...templateAttributes,
dangerouslySetInnerHTML: {
__html: [...shadowContents].join(''),
__html: collectResultSync(shadowContents),
},
});

Expand Down
26 changes: 25 additions & 1 deletion packages/labs/ssr-react/src/lib/node/wrap-jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@ import type {jsxDEV} from 'react/jsx-dev-runtime';
import {createElement, type ReactNode, type ElementType} from 'react';
import {renderCustomElement} from './render-custom-element.js';
import {isCustomElement} from '../utils.js';
import {collectResultSync} from '@lit-labs/ssr/lib/render-result.js';

/**
* Produces a wrapped jsx-runtime `jsx` function that will server render Lit
* components' shadow DOM.
*
* @param originalJsx The original `jsx` function to wrap.
* @param originalJsxs The original `jsxs` function to be used for creating
* React elements with static children.
* @returns Wrapped `jsx` function to be used for production builds.
*/
export function wrapJsx(originalJsx: typeof jsx, originalJsxs: typeof jsxs) {
return function litPatchedJsx<P extends {children?: ReactNode}>(
type: ElementType<P>,
Expand All @@ -24,7 +34,7 @@ export function wrapJsx(originalJsx: typeof jsx, originalJsxs: typeof jsxs) {
const templateShadowRoot = createElement('template', {
...templateAttributes,
dangerouslySetInnerHTML: {
__html: [...shadowContents].join(''),
__html: collectResultSync(shadowContents),
},
});

Expand All @@ -43,6 +53,13 @@ export function wrapJsx(originalJsx: typeof jsx, originalJsxs: typeof jsxs) {
};
}

/**
* Produces a wrapped jsx-runtime `jsxs` function that will server render Lit
* components' shadow DOM.
*
* @param originalJsxs The original `jsxs` function to wrap.
* @returns Wrapped `jsxs` function to be used for production builds.
*/
export function wrapJsxs(originalJsxs: typeof jsxs) {
return function litPatchedJsxs<P extends {children: ReactNode[]}>(
type: ElementType<P>,
Expand Down Expand Up @@ -76,6 +93,13 @@ export function wrapJsxs(originalJsxs: typeof jsxs) {
};
}

/**
* Produces a wrapped jsx-dev-runtime `jsxDEV` function that will server render
* Lit components' shadow DOM.
*
* @param originalJsxDEV The original `jsxDEV` function to wrap.
* @returns Wrapped `jsxs` function to be used for development builds.
*/
export function wrapJsxDev(originalJsxDEV: typeof jsxDEV) {
return function litPatchedJsxDev<
P extends {children?: ReactNode[] | ReactNode},
Expand Down
8 changes: 4 additions & 4 deletions packages/labs/ssr-react/src/node/enable-lit-ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ import {wrapCreateElement} from '../lib/node/wrap-create-element.js';
import {wrapJsx, wrapJsxDev, wrapJsxs} from '../lib/node/wrap-jsx.js';

/* eslint-disable @typescript-eslint/no-explicit-any */
// The `.default ||` is used to get around inconsistent behavior with how
// The `.default ??` is used to get around inconsistent behavior with how
// tools like webpack seem to do es module interop.
Object.assign((React as any).default || React, {
Object.assign((React as any).default ?? React, {
createElement: wrapCreateElement(React.createElement),
});
if (process.env.NODE_ENV === 'production') {
Object.assign((ReactJSXRuntime as any).default || ReactJSXRuntime, {
Object.assign((ReactJSXRuntime as any).default ?? ReactJSXRuntime, {
jsx: wrapJsx(ReactJSXRuntime.jsx, ReactJSXRuntime.jsxs),
jsxs: wrapJsxs(ReactJSXRuntime.jsxs),
});
} else {
Object.assign((ReactJSXDevRuntime as any).default || ReactJSXDevRuntime, {
Object.assign((ReactJSXDevRuntime as any).default ?? ReactJSXDevRuntime, {
jsxDEV: wrapJsxDev(ReactJSXDevRuntime.jsxDEV),
});
}
Expand Down

0 comments on commit fe8d064

Please sign in to comment.