question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Client only components with Vue 3

See original GitHub issue

I wrote a little component that includes third party packages that cannot be rendered server side (midi-player-js and soundfont-player; they are using AudioContext and XMLHttpRequest). Following the docs the best way to solve this problem would be to use dynamic imports. So shouldn’t it be enough to just use defineAsyncComponent because Vue wraps the component into a Promise?

<script setup>
// pages/song.page.vue
const MidiPlayer = defineAsyncComponent(() => import('../../components/MidiPlayer.vue'));
</script>

<template>
    <MidiPlayer />
</template>

But if I use it like this the server still tries to render the component and throws XMLHttpRequest is not defined when running npm run dev. With a condition on the component to only render it in browser it still failes with AudioContext is not defined since the component gets loaded in SSR even if it’s not displayed in the template.

<script setup>
// pages/song.page.vue
const isBrowser = typeof window !== 'undefined';
const MidiPlayer = defineAsyncComponent(() => import('../../components/MidiPlayer.vue'));
</script>

<template>
    <MidiPlayer v-if="isBrowser" />
</template>

So I wrote a litte <ClientOnly> component:

// components/ClientOnly.js
import { h } from 'vue';

const isBrowser = typeof window !== 'undefined';

export default {
    setup(props, { slots }) {
        const slot = slots.default ? slots.default() : [];
        return () => (isBrowser ? h('div', {}, [slot]) : h('div'));
    },
};

This seems to work better but I get an error: Hydration completed but contains mismatches. Is there a way to prevent this from happening?

At the end the best way to do this for me was to add an additional component AsyncMidiPlayer:

// components/AsyncMidiPlayer.js
import { defineAsyncComponent, h } from 'vue';

const isBrowser = typeof window !== 'undefined';

const MidiPlayer = defineAsyncComponent(() => import('./MidiPlayer.vue'));

export default {
    setup(props, context) {
        return () => isBrowser ? h(MidiPlayer, {...props,...context.attrs,}): h('div');
    },
};

And to use it like this:

<script setup>
// pages/song.page.vue
import AsyncMidiPlayer from '../components/AsyncMidiPlayer.js';
</script>

<template>
    <AsyncMidiPlayer  />
</template>

But since I have multiple components that cannot be interpreted server side I would like to have a better solution than writing a custom wrapper for each of them. I was not able to create a generic version of this because the import source needs to be specific (I ran into The above dynamic import cannot be analyzed by vite.). I’m sure there is a better solution for this. Did anyone find a better solution to this than me? It would be nice to extend the vite-plugin-ssr docs with a working vue 3 example.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
DoubleJ-Gcommented, Mar 19, 2022

I’ve used the ClientOnly component from vitepress with no issues ClientOnly.ts

Read more comments on GitHub >

github_iconTop Results From Across the Web

Turbo Tutorial | Nuxt 3: How to add client only components
Learn how to use client and server components in Nuxt 3Find the code for this tutorial here: ...
Read more >
Client-only Nuxt 3 Vue plugin - Stack Overflow
So I guess my question is how do I create a client-only Vue component using Nuxt 3 plugins? Or is there an entirely...
Read more >
API: The <client-only> Component - NuxtJS
This component is used to purposely render a component only on client-side. To import a component only on the client, register the component...
Read more >
vue-client-only - npm
Vue component to wrap non SSR friendly components. Latest version: 2.1.0, last published: 2 years ago. Start using vue-client-only in your ...
Read more >
Vue 3 SSR - Missing Client Only Component : r/vuejs - Reddit
From what I can tell vue-client-only (https://github.com/egoist/vue-client-only) which is used by Nuxt does not support Vue 3 due to event API ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found