aboutsummaryrefslogtreecommitdiff
path: root/packages/integrations/react/server-v17.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/react/server-v17.js')
-rw-r--r--packages/integrations/react/server-v17.js73
1 files changed, 73 insertions, 0 deletions
diff --git a/packages/integrations/react/server-v17.js b/packages/integrations/react/server-v17.js
new file mode 100644
index 000000000..4e577883a
--- /dev/null
+++ b/packages/integrations/react/server-v17.js
@@ -0,0 +1,73 @@
+import React from 'react';
+import ReactDOM from 'react-dom/server.js';
+import StaticHtml from './static-html.js';
+
+const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
+const reactTypeof = Symbol.for('react.element');
+
+function check(Component, props, children) {
+ // Note: there are packages that do some unholy things to create "components".
+ // Checking the $$typeof property catches most of these patterns.
+ if (typeof Component === 'object') {
+ return Component['$$typeof']?.toString().slice('Symbol('.length).startsWith('react');
+ }
+ if (typeof Component !== 'function') return false;
+ if (Component.name === 'QwikComponent') return false;
+
+ if (Component.prototype != null && typeof Component.prototype.render === 'function') {
+ return React.Component.isPrototypeOf(Component) || React.PureComponent.isPrototypeOf(Component);
+ }
+
+ let isReactComponent = false;
+ function Tester(...args) {
+ try {
+ const vnode = Component(...args);
+ if (vnode && vnode['$$typeof'] === reactTypeof) {
+ isReactComponent = true;
+ }
+ } catch {}
+
+ return React.createElement('div');
+ }
+
+ renderToStaticMarkup(Tester, props, children, {});
+
+ return isReactComponent;
+}
+
+function renderToStaticMarkup(Component, props, { default: children, ...slotted }, metadata) {
+ delete props['class'];
+ const slots = {};
+ for (const [key, value] of Object.entries(slotted)) {
+ const name = slotName(key);
+ slots[name] = React.createElement(StaticHtml, { value, name });
+ }
+ // Note: create newProps to avoid mutating `props` before they are serialized
+ const newProps = {
+ ...props,
+ ...slots,
+ };
+ const newChildren = children ?? props.children;
+ if (newChildren != null) {
+ newProps.children = React.createElement(StaticHtml, {
+ // Adjust how this is hydrated only when the version of Astro supports `astroStaticSlot`
+ hydrate: metadata.astroStaticSlot ? !!metadata.hydrate : true,
+ value: newChildren,
+ });
+ }
+ const vnode = React.createElement(Component, newProps);
+ let html;
+ if (metadata?.hydrate) {
+ html = ReactDOM.renderToString(vnode);
+ } else {
+ html = ReactDOM.renderToStaticMarkup(vnode);
+ }
+ return { html };
+}
+
+export default {
+ name: '@astrojs/react',
+ check,
+ renderToStaticMarkup,
+ supportsAstroStaticSlot: true,
+};