Elderjs / elderjs

Elder.js is an opinionated static site generator and web framework for Svelte built with SEO in mind.

Home Page:https://elderguide.com/tech/elderjs/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Handle hydration inside hydration (resolve nested hydration)

dmitrysmagin opened this issue · comments

I have a following scenario:
There are some pages with several hydrated components.
However, I need two variants of site build: 'live-update' and 'static'.
Live-update will monitor some data from CMS system and re-render the page if the data there changes without the need to rebuild the whole site. For this purpose I need the whole page to be a hydrated component, and that's where the problem of nested hydration comes.

The scheme to handle this is the following. There's a wrapper in route template:

{#if process.env.LIVE_UPDATE}
    <ComponentPage hydrate-client={{ prop: null }} />
{:else}
    <ComponentPage prop={null} />
{/if}

And now to resolve nested components inside ComponentPage another wrapper is needed:

{#if process.env.componentType === 'server'}
    <NestedComponent hydrate-client={{ prop2: null }} />
{:else}
    <NestedComponent prop2={null} />
{/if}

However, this brings error in @elderjs/elderjs/build/partialHydration/mountComponentsInHtml.js with this piece of code:

        if (hydrateOptions) {
            throw new Error(`Client side hydrated component is attempting to hydrate another sub component "${hydrateComponentName}." This isn't supported. \n
             Debug: ${JSON.stringify({
                hydrateOptions,
                hydrateComponentName,
                hydrateComponentProps,
                hydrateComponentOptions,
            })}
            `);
        }

What's curious, this code could be commented out and everything will work as expected, because, in fact, nested hydration never actually happens (process.env.componentType resolves this).

Keeping all that above in mind, I'd like to ask if it's possible to make this behavior default or automatic without a wrapper.
So, hydrate-client={{prop: null}} will automatically be changed into prop={null} for all nested hydrated components, or, at least gave only a warning.

commented

Looks like something I was trying to solve in 23ddb74#diff-8dbdaa04b760b0b6f61e99750b86f672deb58b0f165df0dac1416e941e89832fR24 - let svelte compiler handle the template for loading another (hydrated) component using {#if options.loading ...}.

In that commit, you can use the loading options to control its behavior:

<ComponentPage hydrate-client={{ prop: null }} hydrate-options={{loading: process.env.LIVE_UPDATE ? 'lazy' : 'none'}} />
<NestedComponent hydrate-client={{ prop2: null }} hydrate-options={{loading: process.env.componentType === "server" ? "lazy" : "none"}} />

But then it was reverted. In the future Elderjs will be able to load hydrated components from multiple frameworks, so writing something like <SimpleVueComponent /> in svelte template doesn't really make sense.

Or we have to improve the template to something like:

{#if hydrateOptions.loading === 'none' && componentType === 'svelte'}
  ... insert component literally ...
{#else}
  ... insert partial hydration placeholder ...
{/if}

Just have to scan the file tree to determine component type from its name.

commented

As a quick fix, maybe we can change that error into a warning so it won't interrupt the build.

commented

Maybe this should be handled at compile time? When compiling client components, we can replace

<Component hydrate-client={props} />

with

<Component {...props} />

instead of

<ejswrapper data-ejs-component="Component" data-ejs-props={JSON.stringify(props)} data-...
commented

Please try #258. You can install that branch by running:

npm install Elderjs/elderjs#fix/nest-hydrate