vue-lazy-hydration
Lazy hydration of server-side rendered Vue.js components.
WARNING: Beta stage
This plugin is currently in an early beta stage. Although everything seems to work fine in combination with the applications I tested it with, there might be certain cases I haven't considered. I'd be very happy if you test it with your own projects and report back if it works for you.
Use at your own risk.
Motivation
vue-lazy-hydration
is a renderless Vue.js component to improve Estimated Input Latency and Time to Interactive of server-side rendered Vue.js applications. This can be achieved by using lazy hydration to delay the hydration of pre-rendered HTML.
Install
npm install vue-lazy-hydration
import LazyHydrate from 'vue-lazy-hydration';
export default {
components: {
LazyHydrate,
},
};
Basic example
In the example below you can see the four hydration modes in action.
<template>
<div class="ArticlePage">
<LazyHydrate when-idle>
<ImageSlider/>
</LazyHydrate>
<LazyHydrate ssr-only>
<ArticleContent :content="article.content"/>
</LazyHydrate>
<LazyHydrate when-visible>
<AdSlider/>
</LazyHydrate>
<LazyHydrate on-interaction>
<CommentForm :article-id="article.id"/>
</LazyHydrate>
<LazyHydrate on-interaction="click">
<CommentForm :article-id="article.id"/>
</LazyHydrate>
<LazyHydrate when-visible>
<ImageSlider/>
<ArticleContent :content="article.content"/>
<AdSlider/>
</LazyHydrate>
</div>
</template>
<script>
import LazyHydrate from 'vue-lazy-hydration';
export default {
components: {
LazyHydrate,
AdSlider: () => import('./AdSlider.vue'),
ArticleContent: () => import('./ArticleContent.vue'),
CommentForm: () => import('./CommentForm.vue'),
ImageSlider: () => import('./ImageSlider.vue'),
},
};
</script>
- Because it is at the very top of the page, the
ImageSlider
should be hydrated eventually, but we can wait until the browser is idle. - The
ArticleContent
component is only loaded in SSR mode, which means it never gets hydrated in the browser, which also means it will never be interactive (static content only). - Next we can see the
AdSlider
beneath the article content, this component will most likely not be visible initially so we can delay hydration until the point it becomes visible. - At the very bottom of the page we want to render a
CommentForm
but because most people only read the article and don't leave a comment, we can save resources by only hydrating the component whenever it actually receives focus.
Multiple root nodes
Usually vue-lazy-hydration
does not render a DOM element itself if only a single component is nested inside <LazyHydrate>
. If you decide to render multiple components inside of a single <LazyHydrate>
tag, a wrapper <div>
with style="display: contents"
is added. Adding display: contents
makes that the wrapper <div>
doesn't generate any box.
Advanced
Manualy trigger hydration
Sometimes you might want to prevent a component from loading initially but you want to activate it on demand if a certain action is triggered. You can do this by manually triggering the component to hydrate like you can see in the following example.
<template>
<div class="MyComponent">
<button @click="editModeActive = true">
Activate edit mode
</button>
<LazyHydrate ssr-only :trigger-hydration="editModeActive">
<UserSettingsForm :editable="editModeActive"/>
</LazyHydrate>
</div>
</template>
<script>
import LazyHydrate from 'vue-lazy-hydration';
export default {
components: {
LazyHydrate,
UserSettingsForm: () => import('./UserSettingsForm.vue'),
},
data() {
return {
editModeActive: false,
};
},
};
</script>
Benchmarks
Without lazy hydration
With lazy hydration
Caveats
This plugin will not work as advertised if you're not using it in combination with SSR. Although it should work with every pre-rendering approach (like Prerender SPA Plugin, Gridsome, ...) I've only tested it with Nuxt.js so far.
Articles
Credits
The code of the current implementation of this package is based on a similar package created by Rahul Kadyan. Thanks to his code I'm finally able to build a clean solution for what I dreamed of when I created the abomination.
About
Author
Markus Oberlehner
Website: https://markus.oberlehner.net
Twitter: https://twitter.com/MaOberlehner
PayPal.me: https://paypal.me/maoberlehner
Patreon: https://www.patreon.com/maoberlehner
License
MIT