3

I am using Vite JS with Vue 3 for a single page application with server side rendering.

I know that the JS that can only execute on client side must be done on hydration, but is it possible to do so with packages?

My situation is that I want to be able to use Headless UI (for Tailwind UI) and it works fine as long as the app is launched as a Single Page App. When it is launched with SSR, this error occurs:

[Vue warn]: Unhandled error during execution of setup function


at <Dialog as="div" static="" class="fixed z-10 inset-0 overflow-y-auto"  ... >
ReferenceError: window is not defined
    at useWindowEvent (C:\test\node_modules\.pnpm\@[email protected][email protected]\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:408:3)
    at useFocusTrap (C:\test\node_modules\.pnpm\@[email protected][email protected]\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:486:3)
    at setup (C:\test\node_modules\.pnpm\@[email protected][email protected]\node_modules\@headlessui\vue\dist\headlessui.cjs.development.js:1052:5)
    at callWithErrorHandling (C:\test\node_modules\.pnpm\@[email protected]\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:156:22)
    at setupStatefulComponent (C:\test\node_modules\.pnpm\@[email protected]\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6488:29)
    at setupComponent (C:\test\node_modules\.pnpm\@[email protected]\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:6449:11)
    at renderComponentVNode (C:\test\node_modules\.pnpm\@[email protected][email protected]\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:160:17)
    at renderVNode (C:\test\node_modules\.pnpm\@[email protected][email protected]\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:263:22)
    at renderComponentSubTree (C:\test\node_modules\.pnpm\@[email protected][email protected]\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:228:13)
    at renderComponentVNode (C:\test\node_modules\.pnpm\@[email protected][email protected]\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:173:16)

I understand the error comes for the window property not being accessible on the server side, but this is setup by the package itself.

Is there anyway to tell Vite JS SSR to not execute the JS on that package unless it's on the client side?

Here is the content of the vue component that causes the error (on SSR execution only, Dialog is coming from Headless UI):

<template>
  <TransitionRoot as="template" :show="open">
    <Dialog as="div" static class="fixed z-10 inset-0 overflow-y-auto" @close="open = false" :open="open">
      <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
        TEST
      </div>
    </Dialog>
  </TransitionRoot>
</template>

<script>
import { ref } from 'vue'
import { Dialog, TransitionRoot } from '@headlessui/vue'

export default {
  components: {
    Dialog,
    TransitionRoot
  },
  setup() {
    const open = ref(true)

    return {
      open,
    }
  },
}
</script>

PS: I used this boilerplate project if you need reference for config: https://github.com/frandiox/vitesse-ssr-template

2 Answers 2

1

you should import and use that package only on client side.

for import only in client side you can use require instead of import like that:

let headlessui
if (process.browser) headlessui= require('@headlessui/vue')

and then in your template, you can put all client side components in <client-only></client-only> tag:

<client-only>
    <TransitionRoot as="template" :show="open">
        <Dialog as="div" static class="fixed z-10 inset-0 overflow-y-auto" @close="open = false" :open="open">
          <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text- center sm:block sm:p-0">
            TEST
          </div>
        </Dialog>
     </TransitionRoot>
<client-only>
Sign up to request clarification or add additional context in comments.

2 Comments

But that means I wouldn't be able to use the components at all on SSR right? Like, I want them to still display on SSR, just not to execute JS unless in client?
you cant separate js and template of components. they work together. check which components are only executable on the client side and only put them to client-only tag. other components still can render on the server side
1

I was having similar issue in Vue2 i was actually trying to use apexchart and after build, i get Reference error window is not defined what i did was i installed vue-client-only then in my entry file i added

if (typeof window !== 'undefined') {
    const VueApexCharts = require('vue-apexcharts')
    Vue.component('ApexChart', VueApexCharts)
  }

and i wrapped this with the component

<template>
    <client-only>
                <div id="chart">
                  <apex-chart type="radar" height="350" :options="chartOptions" :series="series"></apex-chart>
                </div>
    </client-only>
</template>
<script>
import ClientOnly from 'vue-apexcharts'
export default {
  components: {
ClientOnly
}}
</script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.