0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-02-10 22:38:53 -05:00

feat: get react integration 19-ready

This commit is contained in:
bholmesdev 2024-04-26 18:01:59 -04:00
parent c238aa81ee
commit d0eae83cd7
5 changed files with 59 additions and 115 deletions

View file

@ -1,22 +0,0 @@
import { createElement } from 'react';
import { hydrate, render, unmountComponentAtNode } from 'react-dom';
import StaticHtml from './static-html.js';
export default (element) =>
(Component, props, { default: children, ...slotted }, { client }) => {
for (const [key, value] of Object.entries(slotted)) {
props[key] = createElement(StaticHtml, { value, name: key });
}
const componentEl = createElement(
Component,
props,
children != null ? createElement(StaticHtml, { value: children }) : children
);
const isHydrate = client !== 'only';
const bootstrap = isHydrate ? hydrate : render;
bootstrap(componentEl, element);
element.addEventListener('astro:unmount', () => unmountComponentAtNode(element), {
once: true,
});
};

View file

@ -60,10 +60,10 @@
"vite": "^5.2.10"
},
"peerDependencies": {
"@types/react": "^17.0.50 || ^18.0.21",
"@types/react-dom": "^17.0.17 || ^18.0.6",
"react": "^17.0.2 || ^18.0.0",
"react-dom": "^17.0.2 || ^18.0.0"
"@types/react": "^18.0.21 || npm:types-react@beta",
"@types/react-dom": "^18.0.6 || npm:types-react@beta",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"engines": {
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"

View file

@ -1,88 +0,0 @@
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 errorIsComingFromPreactComponent(err) {
return (
err.message &&
(err.message.startsWith("Cannot read property '__H'") ||
err.message.includes("(reading '__H')"))
);
}
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 error = null;
let isReactComponent = false;
function Tester(...args) {
try {
const vnode = Component(...args);
if (vnode && vnode['$$typeof'] === reactTypeof) {
isReactComponent = true;
}
} catch (err) {
if (!errorIsComingFromPreactComponent(err)) {
error = err;
}
}
return React.createElement('div');
}
renderToStaticMarkup(Tester, props, children, {});
if (error) {
throw error;
}
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 {
check,
renderToStaticMarkup,
supportsAstroStaticSlot: true,
};

View file

@ -1,6 +1,6 @@
import opts from 'astro:react:opts';
import React from 'react';
import ReactDOM from 'react-dom/server';
import ReactDOM from 'react-dom/server.browser';
import { incrementId } from './context.js';
import StaticHtml from './static-html.js';

54
pnpm-lock.yaml generated
View file

@ -4847,6 +4847,27 @@ importers:
specifier: ^5.2.10
version: 5.2.10(@types/node@18.19.31)(sass@1.75.0)
packages/integrations/react/test/fixtures/react-19:
dependencies:
'@astrojs/react':
specifier: workspace:*
version: link:../../..
'@types/react':
specifier: npm:types-react@beta
version: /types-react@19.0.0-beta.1
'@types/react-dom':
specifier: npm:types-react-dom@beta
version: /types-react-dom@19.0.0-beta.1
astro:
specifier: workspace:*
version: link:../../../../../astro
react:
specifier: 19.0.0-beta-94eed63c49-20240425
version: 19.0.0-beta-94eed63c49-20240425
react-dom:
specifier: 19.0.0-beta-94eed63c49-20240425
version: 19.0.0-beta-94eed63c49-20240425(react@19.0.0-beta-94eed63c49-20240425)
packages/integrations/react/test/fixtures/react-component:
dependencies:
'@astrojs/react':
@ -14474,6 +14495,18 @@ packages:
react: 18.2.0
scheduler: 0.23.0
/react-dom@19.0.0-beta-94eed63c49-20240425(react@19.0.0-beta-94eed63c49-20240425):
resolution: {integrity: sha512-V0uHW7Xd0u/LDlmFO8sJ9TTNizAESS+pexJNOi3KbOU1taf2gUO5J8YIWis60xcQbh7YBqSklyYIIq3DfiKz3Q==}
peerDependencies:
react: 19.0.0-beta-94eed63c49-20240425
peerDependenciesMeta:
react:
optional: true
dependencies:
react: 19.0.0-beta-94eed63c49-20240425
scheduler: 0.25.0-beta-94eed63c49-20240425
dev: false
/react-is@18.2.0:
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
dev: false
@ -14489,6 +14522,11 @@ packages:
dependencies:
loose-envify: 1.4.0
/react@19.0.0-beta-94eed63c49-20240425:
resolution: {integrity: sha512-BPPKh5bZwcpw/Dgfh3A0MoU1GSl2edR2JggCq3QPdghQsrFg1aBuMkul5YB4rpII400RYq9VC5eF5Nm3spx0gA==}
engines: {node: '>=0.10.0'}
dev: false
/read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
dependencies:
@ -14982,6 +15020,10 @@ packages:
dependencies:
loose-envify: 1.4.0
/scheduler@0.25.0-beta-94eed63c49-20240425:
resolution: {integrity: sha512-U8hoOV7uut5E8cMvRSMikEBBqLXfv2BpdxUsG45euaOfnqEgFrCdLLh6ydM+YBJ36+28olXMNmK2PFFzeg4UdQ==}
dev: false
/scslre@0.3.0:
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
engines: {node: ^14.0.0 || >=16.0.0}
@ -16061,6 +16103,18 @@ packages:
possible-typed-array-names: 1.0.0
dev: true
/types-react-dom@19.0.0-beta.1:
resolution: {integrity: sha512-fXQfv6OQOXxmgNQ7RuhX615Wx4680LqVbrEbxch+ZQ56ZDAZKXptLl3XoHaHU31Yd2xiig/VlXzohCexKXNzBQ==}
dependencies:
'@types/react': 18.2.79
dev: false
/types-react@19.0.0-beta.1:
resolution: {integrity: sha512-gQpuPdi+Gu+nIFmhnFLINkGQ4j0eRY7olV3lzncFJy2g5TfnSEFD1xU86u5KgRytFswwZ5pGEPWEizefwPaxTw==}
dependencies:
csstype: 3.1.3
dev: false
/typesafe-path@0.2.2:
resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==}