server-v17.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import React from 'react';
  2. import ReactDOM from 'react-dom/server.js';
  3. import StaticHtml from './static-html.js';
  4. const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
  5. const reactTypeof = Symbol.for('react.element');
  6. function errorIsComingFromPreactComponent(err) {
  7. return (
  8. err.message &&
  9. (err.message.startsWith("Cannot read property '__H'") ||
  10. err.message.includes("(reading '__H')"))
  11. );
  12. }
  13. function check(Component, props, children) {
  14. // Note: there are packages that do some unholy things to create "components".
  15. // Checking the $$typeof property catches most of these patterns.
  16. if (typeof Component === 'object') {
  17. return Component['$$typeof']?.toString().slice('Symbol('.length).startsWith('react');
  18. }
  19. if (typeof Component !== 'function') return false;
  20. if (Component.name === 'QwikComponent') return false;
  21. if (Component.prototype != null && typeof Component.prototype.render === 'function') {
  22. return React.Component.isPrototypeOf(Component) || React.PureComponent.isPrototypeOf(Component);
  23. }
  24. let error = null;
  25. let isReactComponent = false;
  26. function Tester(...args) {
  27. try {
  28. const vnode = Component(...args);
  29. if (vnode && vnode['$$typeof'] === reactTypeof) {
  30. isReactComponent = true;
  31. }
  32. } catch (err) {
  33. if (!errorIsComingFromPreactComponent(err)) {
  34. error = err;
  35. }
  36. }
  37. return React.createElement('div');
  38. }
  39. renderToStaticMarkup(Tester, props, children, {});
  40. if (error) {
  41. throw error;
  42. }
  43. return isReactComponent;
  44. }
  45. function renderToStaticMarkup(Component, props, { default: children, ...slotted }, metadata) {
  46. delete props['class'];
  47. const slots = {};
  48. for (const [key, value] of Object.entries(slotted)) {
  49. const name = slotName(key);
  50. slots[name] = React.createElement(StaticHtml, { value, name });
  51. }
  52. // Note: create newProps to avoid mutating `props` before they are serialized
  53. const newProps = {
  54. ...props,
  55. ...slots,
  56. };
  57. const newChildren = children ?? props.children;
  58. if (newChildren != null) {
  59. newProps.children = React.createElement(StaticHtml, {
  60. // Adjust how this is hydrated only when the version of Astro supports `astroStaticSlot`
  61. hydrate: metadata.astroStaticSlot ? !!metadata.hydrate : true,
  62. value: newChildren,
  63. });
  64. }
  65. const vnode = React.createElement(Component, newProps);
  66. let html;
  67. if (metadata?.hydrate) {
  68. html = ReactDOM.renderToString(vnode);
  69. } else {
  70. html = ReactDOM.renderToStaticMarkup(vnode);
  71. }
  72. return { html };
  73. }
  74. export default {
  75. check,
  76. renderToStaticMarkup,
  77. supportsAstroStaticSlot: true,
  78. };