Skip to content

Instantly share code, notes, and snippets.

@ngryman
Last active July 9, 2017 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ngryman/6d32b8366ea51231368061eae32daf97 to your computer and use it in GitHub Desktop.
Save ngryman/6d32b8366ea51231368061eae32daf97 to your computer and use it in GitHub Desktop.
Hydration

The aim of hydratation is to avoid trashing out of existing DOM rendered by SSR, but use them and attach eventual event listeners (like a regular patch pass).

Hydratation would happen at the app level and at the first render. Basically it needs a way to know that some part of the DOM tree is something to patch so it does not have to mount.

Before going on, some terminology:

  • The root is the root DOM node generated by HyperApp, the toplevel DOM element.
  • The host is the DOM node that will hold the root, it's currently defined as app.root.

The current implementation simply appends the root to the host. So if the host already contains children, they are not removed. That is an important feature because it allows non-HyperApp elements to live aside the root, sharing the same host.

Let's say we have a very basic app that produce the following DOM elements:

<div class="app">
  <h1>Counters</h1>
  <button class="counter">1</button>
</div>

The root of the app is div.app. Now lets say we have an already existing document containing terrible stuff like social crap:

<body>
  <div id="fb-root"></div>
  <script src="my.very.useless.facebook-script.js" />
</body>

Currently we can implicitly inject the app using body as the host, the result will be:

<body>
  <div id="fb-root"></div>
  <script src="my.very.useless.facebook-script.js" />
  <div class="app">
    <h1>Counters</h1>
    <button class="counter">1</button>
  </div>
</body>

Now imagine we use SSR, the initial document becomes:

<body>
  <div id="fb-root"></div>
  <script src="my.very.useless.facebook-script.js" />
  <div class="app">
    <h1>Counters</h1>
    <button class="counter">1</button>
  </div>
</body>

And when HyperApp kicks in, it becomes:

<body>
  <div id="fb-root"></div>
  <script src="my.very.useless.facebook-script.js" />
  <div class="app">
    <h1>Counters</h1>
    <button class="counter">1</button>
  </div>
  <div class="app">
    <h1>Counters</h1>
    <button class="counter">1</button>
  </div>
</body>

So it basically duplicates things because it has no information to distinct initial markup from SSRed markup.

The solution I propose is to put a marker attribute on the root rendered DOM, let's ssr. So the initial markup now becomes this:

<body>
  <div id="fb-root"></div>
  <script src="my.very.useless.facebook-script.js" />
  <div class="app" ssr>
    <h1>Counters</h1>
    <button class="counter">1</button>
  </div>
</body>

When HyperApp kicks in, it will simply seek for the first child of the host (aka app.root) having the attribute ssr. If it finds it, it will considered as the root (aka element in HyperApp source code) and will be patched. If no ssr child is found, the root (aka element in Hyper source code) is left to undefined and patch will mount the app (aka create all DOM nodes).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment