From 304dbada5305e1e1e9993f052b3aa04324229980 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Thu, 13 Jul 2023 17:25:26 -0500 Subject: [PATCH] wip: support true react vnodes in renderer --- packages/integrations/react/package.json | 3 +- packages/integrations/react/server.js | 12 +++++- packages/integrations/react/vnode-children.js | 38 +++++++++++++++++++ pnpm-lock.yaml | 7 ++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 packages/integrations/react/vnode-children.js diff --git a/packages/integrations/react/package.json b/packages/integrations/react/package.json index fa68cd5f0..9094a9f73 100644 --- a/packages/integrations/react/package.json +++ b/packages/integrations/react/package.json @@ -45,7 +45,8 @@ }, "dependencies": { "@babel/core": "^7.22.5", - "@babel/plugin-transform-react-jsx": "^7.22.5" + "@babel/plugin-transform-react-jsx": "^7.22.5", + "ultrahtml": "^1.2.0" }, "devDependencies": { "@types/react": "^17.0.62", diff --git a/packages/integrations/react/server.js b/packages/integrations/react/server.js index 8c02c4b26..e7931dcb9 100644 --- a/packages/integrations/react/server.js +++ b/packages/integrations/react/server.js @@ -43,6 +43,12 @@ async function check(Component, props, children) { return React.createElement('div'); } + if (props['use:vnode']) { + const convert = await import('./vnode-children.js').then(mod => mod.default); + delete props['use:vnode']; + children = convert(children); + } + await renderToStaticMarkup(Tester, props, children, {}); if (error) { @@ -85,7 +91,11 @@ async function renderToStaticMarkup(Component, props, { default: children, ...sl ...slots, }; const newChildren = children ?? props.children; - if (newChildren != null) { + if (props['use:vnode']) { + const convert = await import('./vnode-children.js').then(mod => mod.default); + delete props['use:vnode']; + newProps.children = convert(children) + } else if (newChildren != null) { newProps.children = React.createElement(StaticHtml, { hydrate: needsHydration(metadata), value: newChildren, diff --git a/packages/integrations/react/vnode-children.js b/packages/integrations/react/vnode-children.js new file mode 100644 index 000000000..b387ecaa3 --- /dev/null +++ b/packages/integrations/react/vnode-children.js @@ -0,0 +1,38 @@ +import { parse, walkSync, DOCUMENT_NODE, ELEMENT_NODE, TEXT_NODE } from 'ultrahtml' +import { createElement, Fragment } from 'react'; + +export default function convert(children) { + const nodeMap = new WeakMap(); + let doc = parse(children.default.toString().trim()); + let root = createElement(Fragment, { children: [] }); + + walkSync(doc, (node, parent, index) => { + let newNode = {}; + if (node.type === DOCUMENT_NODE) { + nodeMap.set(node, root); + } else if (node.type === ELEMENT_NODE) { + const { class: className, ...props } = node.attributes; + newNode = createElement(node.name, { ...props, className, children: [] }); + nodeMap.set(node, newNode); + if (parent) { + const newParent = nodeMap.get(parent); + newParent.props.children[index] = newNode; + + } + } else if (node.type === TEXT_NODE) { + newNode = node.value.trim(); + if (newNode.trim()) { + if (parent) { + const newParent = nodeMap.get(parent); + if (parent.children.length === 1) { + newParent.props.children[0] = newNode; + } else { + newParent.props.children[index] = newNode; + } + } + } + } + }); + + return root.props.children; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f44e8f46d..203bc7202 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4720,6 +4720,9 @@ importers: '@babel/plugin-transform-react-jsx': specifier: ^7.22.5 version: 7.22.5(@babel/core@7.22.5) + ultrahtml: + specifier: ^1.2.0 + version: 1.2.0 devDependencies: '@types/react': specifier: ^17.0.62 @@ -17114,6 +17117,10 @@ packages: resolution: {integrity: sha512-P24ulZdT9UKyQuKA1IApdAZ+F9lwruGvmKb4pG3+sMvR3CjN0pjawPnxuSABHQFB+XqnB35TVXzJPOBYjCv6Kw==} dev: false + /ultrahtml@1.2.0: + resolution: {integrity: sha512-vxZM2yNvajRmCj/SknRYGNXk2tqiy6kRNvZjJLaleG3zJbSh/aNkOqD1/CVzypw8tyHyhpzYuwQgMMhUB4ZVNQ==} + dev: false + /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: