Skip to content
This repository has been archived by the owner on Jul 28, 2023. It is now read-only.

Add lazy hydration techniques: idle and view #75

Closed
DAreRodz opened this issue Sep 22, 2022 · 6 comments
Closed

Add lazy hydration techniques: idle and view #75

DAreRodz opened this issue Sep 22, 2022 · 6 comments

Comments

@DAreRodz
Copy link
Collaborator

We want to add different hydration techniques for blocks as we did for the Island Hydration approach in #12.

At this moment, we can start by adding view and idle and keep adding more in the future.

@DAreRodz DAreRodz changed the title Add lazy hydration techniques ⚛️ Add lazy hydration techniques Sep 22, 2022
@DAreRodz DAreRodz changed the title ⚛️ Add lazy hydration techniques ⚛️ Add lazy hydration techniques: idle and view Sep 22, 2022
@DAreRodz
Copy link
Collaborator Author

For context: we are currently on a challenging quest, trying to find a way to hydrate components after a particular condition is fulfilled (e.g., CPU is idle, component is in view, etc.) This is intimately related to out-of-order hydration, which is another thing we want to achieve and why we are not using Suspense for lazy hydration (Suspense would render components in sequence).

Some of the things we've tried are:

  • A component that re-renders once a promise resolves, producing the same HTML but a different vDOM. (codesandbox)
  • Use hydrate or render to re-hydrate/re-render the whole app once the component is ready. (stackblitz)

So far, with any of the approaches tested above, we've reached the same problem: once a new node appears in the virtual DOM —even though this node's component is a wrapper that simply renders children— that whole branch is unmounted and mounted again.

In the second approach, choosing between hydrate or render would change how the nodes are treated:

  • hydrate maintains the DOM without any changes but re-creates all components, the state, hooks, etc.
  • render keeps everything above the wrapper (nodes, components, state, etc.).

However, there's still hope. 😄

As preact is highly hackable, we could use Preact's Option Hooks API to make changes to the vDOM in a way that the DOM is preserved. @luisherranz has been involved in some conversations with Jason Miller (preact), who gave him some ideas we could explore. We will be working on that next week. 🤞

@luisherranz, feel free to expand this if you feel something is missing. 🙂

@luisherranz
Copy link
Member

Super preliminary yet, but I made it work by manually mutating the vdom as suggested by Jason:

const clientCompParent = window.root.__k.__k[0].__k[2];
const clientComp = h(ClientComponent);
clientComp.__b = clientCompParent.__b + 1;
clientCompParent.__k.forEach((child) => {
  child.__b += 1;
  child.__o = clientComp;
});
clientComp.__k = clientCompParent.__k;
clientComp.__o = clientCompParent;
clientCompParent.__k = [clientComp];

Stackblitz

@luisherranz
Copy link
Member

Even though mutating the previous vdom before the rerender works, doing so on the fly for an undetermined number of internal components is not possible at the moment because in options.vnode you don't know the parent-child relationship, and in options.__b (diff), diffChildren stores a reference to the previous vnode children before calling diff (which is the one that calls options.__b), so it's too late to mutate the previous vnode children: clientCompParent.__k = [clientComp];

We need to know the exact shape of the new vdom before triggering the rerendering. As updating the vdom without updating the DOM is not possible, another possible approach might be:

  • Render the static vdom twice: in the real DOM and in a JS-only node (not appended).
  • Whenever we need to hydrate a client component, hydrate it first on the JS-only vdom
    • Try to prevent side effects from running here (maybe try to block with options.requestAnimationFrame).
  • Mutate the real DOM vdom using the JS-only vdom shape.
  • Hydrate the client component in the real DOM.

But this starts getting too complex and convoluted. I'd leave it for now, keep exploring other things, and come back to this later.

@luisherranz
Copy link
Member

luisherranz commented Sep 26, 2022

Another wild idea: annotate in the DOM the number of component vnodes during the SSR, then insert as many innocuous wrappers as needed in the dom -> vdom step.

@luisherranz
Copy link
Member

luisherranz commented Jan 16, 2023

Now that #124 has landed, maybe we can revisit this for sites without client-side navigations.

@luisherranz
Copy link
Member

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants