Add hydration to Solid renderer (#1479) (#1495)

* feat: add hydration to Solid renderer

* fix: intersection observer, move script to the end

Co-authored-by: Ryan Carniato <ryansolid@gmail.com>
This commit is contained in:
Matthew Phillips 2021-10-05 16:57:51 -04:00 committed by GitHub
parent 584947e862
commit 876569d97a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 15 additions and 20 deletions

View file

@ -1,16 +1,11 @@
import { createComponent } from 'solid-js'; import { hydrate, createComponent } from 'solid-js/web';
import { render } from 'solid-js/web';
export default (element) => (Component, props, childHTML) => { export default (element) => (Component, props, childHTML) => {
// Solid's `render` does not replace the element's children.
// Deleting the root's children is necessary before calling `render`.
element.replaceChildren();
const children = document.createElement('astro-fragment'); const children = document.createElement('astro-fragment');
children.innerHTML = childHTML; children.innerHTML = childHTML;
// Using Solid's `render` method ensures that a `root` is created // Using Solid's `hydrate` method ensures that a `root` is created
// in order to properly handle reactivity. It also handles // in order to properly handle reactivity. It also handles
// components that are not native HTML elements. // components that are not native HTML elements.
render(() => createComponent(Component, { ...props, children }), element); hydrate(() => createComponent(Component, { ...props, children }), element);
}; };

View file

@ -3,7 +3,7 @@ export default {
client: './client', client: './client',
server: './server', server: './server',
knownEntrypoints: ['solid-js', 'solid-js/web', 'solid-js/store', 'solid-js/html', 'solid-js/h'], knownEntrypoints: ['solid-js', 'solid-js/web', 'solid-js/store', 'solid-js/html', 'solid-js/h'],
external: ['solid-js/web/dist/server.cjs', 'solid-js/dist/server.cjs', 'babel-preset-solid'], external: ['solid-js/web/dist/server.cjs', 'solid-js/store/dist/server.cjs', 'solid-js/dist/server.cjs', 'babel-preset-solid'],
jsxImportSource: 'solid-js', jsxImportSource: 'solid-js',
jsxTransformOptions: async ({ isSSR }) => { jsxTransformOptions: async ({ isSSR }) => {
const [{ default: solid }] = await Promise.all([import('babel-preset-solid')]); const [{ default: solid }] = await Promise.all([import('babel-preset-solid')]);
@ -18,6 +18,7 @@ export default {
{ {
cwd: process.cwd(), cwd: process.cwd(),
alias: { alias: {
'solid-js/store': 'solid-js/store/dist/server.cjs',
'solid-js/web': 'solid-js/web/dist/server.cjs', 'solid-js/web': 'solid-js/web/dist/server.cjs',
'solid-js': 'solid-js/dist/server.cjs', 'solid-js': 'solid-js/dist/server.cjs',
}, },

View file

@ -1,24 +1,23 @@
import { createComponent } from 'solid-js'; import { renderToString, ssr, createComponent } from 'solid-js/web/dist/server.cjs';
import { renderToStringAsync, ssr } from 'solid-js/web/dist/server.cjs';
async function check(Component, props, children) { function check(Component, props, children) {
if (typeof Component !== 'function') return false; if (typeof Component !== 'function') return false;
const { html } = await renderToStaticMarkup(Component, props, children); const { html } = renderToStaticMarkup(Component, props, children);
return typeof html === 'string'; return typeof html === 'string';
} }
async function renderToStaticMarkup(Component, props, children) { function renderToStaticMarkup(Component, props, children) {
const html = await renderToStringAsync( const html = renderToString(
() => () => () =>
createComponent(Component, { createComponent(Component, {
...props, ...props,
// In Solid SSR mode, `ssr` creates the expected structure for `children`. // In Solid SSR mode, `ssr` creates the expected structure for `children`.
// In Solid client mode, `ssr` is just a stub. // In Solid client mode, `ssr` is just a stub.
children: ssr([`<astro-fragment>${children}</astro-fragment>`]), children: ssr(`<astro-fragment>${children}</astro-fragment>`),
}) })
); );
return { html }; return { html: html + `<script>window._$HYDRATION||(window._$HYDRATION={events:[],completed:new WeakSet})</script>` };
} }
export default { export default {

View file

@ -1,4 +1,4 @@
import { createComponent } from 'solid-js'; import { ssr } from 'solid-js/web/dist/server.js';
/** /**
* Astro passes `children` as a string of HTML, so we need * Astro passes `children` as a string of HTML, so we need
@ -6,7 +6,7 @@ import { createComponent } from 'solid-js';
*/ */
const StaticHtml = ({ innerHTML }) => { const StaticHtml = ({ innerHTML }) => {
if (!innerHTML) return null; if (!innerHTML) return null;
return () => createComponent('astro-fragment', { innerHTML }); return ssr(`<astro-fragment>${innerHTML }</astro-fragment>`);
}; };
export default StaticHtml; export default StaticHtml;