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:
parent
c238aa81ee
commit
d0eae83cd7
5 changed files with 59 additions and 115 deletions
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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
54
pnpm-lock.yaml
generated
|
@ -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==}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue