Member-only story
Nuxt.js — Best practices for client-side-only contents (client-only / no-ssr)
Not all third party components support server side rendering (SSR). Nuxt.js provides a way for you to exclude those components from the server side rendering phase, which is the <client-only> or <no-ssr> (deprecated) tag.
<template>
<div>
<client-only>
<carousel v-bind:perPage="2">
<slide
v-for="imgUrl in imgUrls"
v-bind:key="imgUrl">
<img v-bind:src="imgUrl">
</slide>
</carousel>
</client-only>
</div>
</template>
When you do this, all the contents within the <client-only> tag will not be rendered during SSR. Those contents will be rendered in the client side after the Vue instance is initialized in the user’s browser. For best practices, here is the decision point that you should consider when using the <client-only> tag — Are contents inside important for SEO?
If contents are important for SEO
Most search engine crawlers do not execute JS when they do the crawling. (Only Google will execute JS as I know.) As a result, the Vue instance is never initialized and those contents will not be visible to crawlers. To deal with this, you should add placeholders, which are displayed before those client-only contents are rendered. The Vue instance will replace the placeholder with the client-only contents once they are loaded.
<template>
<div>
<client-only>
<carousel v-bind:perPage="2">
<slide
v-for="imgUrl in imgUrls"
v-bind:key="imgUrl">
<img v-bind:src="imgUrl">
</slide>
</carousel>
<template slot="placeholder">
<img
v-for="imgUrl in imgUrls"
v-bind:key="imgUrl"
v-bind:src="imgUrl">
</template>
</client-only>
</div>
</template>
This will solve the SEO problem, but there are still other problems we need to handle. As the placeholder is displayed before the client-only contents are rendered, it means users will also see the placeholder before they completely download all the scripts and initialize their Vue instances. Hence, placeholders should be correctly styled as well.
<template>
<div>
<client-only>
<carousel v-bind:perPage="2">
<slide
v-for="imgUrl in imgUrls"
v-bind:key="imgUrl">
<img v-bind:src="imgUrl">
</slide>
</carousel>…