vue-carousel icon indicating copy to clipboard operation
vue-carousel copied to clipboard

Feature Request: add server side rendering (Nuxt.js) to vue-carousel

Open midlantica opened this issue 8 years ago • 37 comments

Newbie. I had vue-carousel running great prior to an update, in nuxt I think. Now it simply won't work.

Running vue-carousel locally in component, Terminal: `[Vue warn]: Error in beforeCreate hook: "ReferenceError: document is not defined"

found in

---> <Carousel> <CarouselShow> at components/CarouselShow.vue <Pages/index.vue> at pages/index.vue <Nuxt> at .nuxt/components/nuxt.vue <Default> at layouts/default.vue <Root>

` And I guess it is in a loop, because Chrome keeps spinning and eventually I get the dialog box "Do you wish to kill process?"

If I run vue-carousel globally I do not get the warning, but my Slides are static and all Slides show up on the page at once.

Help much appreciated.

midlantica avatar Aug 29 '17 15:08 midlantica

This is because there is no document during server side rendering. You can use tag to wrap the carousel after Nuxt v1.0.0-rc7(example)

ckpiggy avatar Sep 04 '17 13:09 ckpiggy

Thank you! 😭

midlantica avatar Sep 05 '17 14:09 midlantica

Nice! 😭

KaronAmI avatar Sep 11 '17 09:09 KaronAmI

Ideally vue-carousel itself would fix this. Vue components should be loadable with SSR by default.

matthew-dean avatar Sep 20 '17 21:09 matthew-dean

You can simply fix this issue using config with SSR setup as @matthew-dean said.

create plugins/vue-carousel.js:

import Vue from 'vue'
import VueCarousel from 'vue-carousel'

Vue.use(VueCarousel)

in nuxt.config.js:

plugins: [{ src: '~plugins/vue-carousel', ssr: false }]

Then it's ready to use!! 🍙

mayognaise avatar Nov 06 '17 20:11 mayognaise

How would I achieve this if I am not using nuxt and using the Hackernews demo ? I have tried using it in the app.js and I get the document error. If I use it anywhere else(entry-client.js). It fails saying content on server does not match the one on client, bails hydration and component is invisible now.

SarasArya avatar Nov 08 '17 11:11 SarasArya

@mayognaise @ckpiggy thanks for the solution it worked. But I want to preload my carousel before sending to the client side, would u please help me with this?

adyontech avatar Nov 09 '17 04:11 adyontech

You can put a v-if on the carousel make the variable true on mounted.

For ex

<template>
  <div v-if="showCarousel">
    <carousel
      ref="mycarousel"
      >
      <slide v-for="some of something">
      </carousel>
  </div>
</template>

<script>
  export default {
    import { Carousel, Slide } from 'vue-carousel';
    data() {
      return {
        showCarousel : false
      }
    }
    mounted() {
      // Vue.use(VueCarousel);
      this.showCarousel = true;
    },
  }
</script>

SarasArya avatar Nov 09 '17 14:11 SarasArya

Honestly, these "solutions" are not good. This is ridiculous. If you use SSR, you do it for a reason! You want all your content to be available for bots, crawlers etc. Any Vue.js component or library should be aware of that and prevent accessing window or document directly without checking for the environment first!

This IS a HUGE BUG and it should be fixed.

iloginow avatar Dec 31 '17 15:12 iloginow

This works for me

Import:

import Carousel from 'vue-carousel/src/Carousel.vue'
import Slide from 'vue-carousel/src/Slide.vue'

Components:

  components: {
    Carousel,
    Slide,
  },

Template (pug)

carousel
    slide(v-for='image in images')
      img(:src='image')

wesssel avatar Feb 07 '18 05:02 wesssel

For it to work seamlessly on DEVELOPMENT MODE and PRODUCTION MODE

improving on @mayognaise and @SarasArya

create plugins/vue-carousel.js:

import Vue from 'vue'
import VueCarousel from 'vue-carousel'

Vue.use(VueCarousel)

in nuxt.config.js:

plugins: [{ src: '~plugins/vue-carousel', ssr: false }]

in your component

<template>
  <div v-if="showCarousel">
    <carousel
      ref="mycarousel"
      >
      <slide v-for="some of something">
      </carousel>
  </div>
</template>

<script>
  export default {
    import { Carousel, Slide } from 'vue-carousel';
    data() {
      return {
        showCarousel : false
      }
    }
    mounted() {
      // Vue.use(VueCarousel);
      this.showCarousel = true;
    },
  }
</script>

This will enable it to work seamlessly on both production and development mode

kingflamez avatar Apr 19 '18 10:04 kingflamez

No update?

terryds avatar Jun 27 '18 07:06 terryds

@terryds no PR has been opened addressing full SSR support yet, is the above workaround not working for you?

quinnlangille avatar Jun 27 '18 13:06 quinnlangille

@quinnlangille it's working without SSR

terryds avatar Jun 27 '18 14:06 terryds

@kingflamez this solution is not working with latest Nuxt, it throws an error like:

ReferenceError: window is not defined

I used both <no-ssr> and nuxt.config.js improvements, no luck.

Defite avatar Oct 07 '18 18:10 Defite

any solution for this problem

heshamelmasry77 avatar Oct 10 '18 12:10 heshamelmasry77

Hey @heshamelmasry77, since we can't seem to have a consistent success or failure with this issue I'm starting to believe it's a nuxt side issue rather than the carousel. I'll leave this chat open as discussion, but since we have documented successful implementations above I don't think anyone is actively pursuing another option

quinnlangille avatar Oct 10 '18 15:10 quinnlangille

I'm using nuxt 1.4.2 and webpack 3.12.0. I tried both with the "local" import inside the component, or using global plugin.

I have no problem at all using the <carousel> inside a <no-ssr> tag up to version 0.11.0. Upgrading vue-carousel to version 0.12.0 or above, the error starts to pop out:

at Object.<anonymous> (/project_dir/node_modules/vue-carousel/dist/vue-carousel.min.js:6:204)```

dappiu avatar Oct 19 '18 12:10 dappiu

any solution for this problem

The only solution for now is to use no-ssr properly :)

<no-ssr placeholder="Loading...">
   <IndexCarousel />
</no-ssr>  

It turned out, that no-ssr can have only one child. Now everything works fine.

Defite avatar Oct 19 '18 15:10 Defite

this works too: https://gist.github.com/podlebar/340c9e7731b319d838eba083bb91a8ba

mix of dynamic import and mounted hook...

podlebar avatar Dec 13 '18 10:12 podlebar

For anyone else facing this issue - the solution by @podlebar above was the only one that worked for me!

matthew-inamdar avatar Mar 09 '19 15:03 matthew-inamdar

I can confirm the @podlebar solution is working with [email protected] and [email protected], but I still see an error on server side:

ERROR [Vue warn]: Failed to resolve async component: () => Promise.resolve(/*! import() /).then(webpack_require.t.bind(null, /! vue-carousel */ "vue-carousel", 7)).then(m => m.Carousel).catch() Reason: ReferenceError: window is not defined

This could be because I was using nuxt dev mode, anyway, to prevent the server from even trying to resolve the import Promise, I modified the arrow functions returning component like this:

this modification generates no errors during server side rendering, and also prevents to hide import errors on the client side

components: {
  Carousel: () => process.browser ? import('vue-carousel').then(m => m.Carousel) : null,
  Slide: () => process.browser ? import('vue-carousel').then(m => m.Slide) : null
}

dappiu avatar Mar 20 '19 12:03 dappiu

components: {
  Carousel: () => process.browser ? import('vue-carousel').then(m => m.Carousel) : null,
  Slide: () => process.browser ? import('vue-carousel').then(m => m.Slide) : null
}

Please note that the solution above with delayed import, for Nuxt is required only when you don't want to make Carousel and Slide components available globally. Otherwise using a Nuxt plugin (loaded with option ssr: true -or mode: 'client' or again ending the file name with client.js for newer Nuxt versions) is all that you have to do, because you don't need to import Carousel and Slide to make them available to your pages and components.

Tested with Nuxt 2.4.5, vue-carousel 0.17.0, instantiating Carousel and Slide components only inside a <no-ssr> element

// plugins/vue-carousel.client.js
import Vue from 'vue'
import VueCarousel from 'vue-carousel'

export default () => {
	Vue.use(VueCarousel)
}
// nuxt.config.js
export default {
    // ...
    plugins: [
        { '~/plugins/vue-carousel.client.js', ssr: false }
    ]
    // ...
}
// pages/show-me-the-carousel.vue

// Since <template> and <no-ssr> strictly require one root element, I'd usually prefer 
// using divs instead of components or custom tags as the only direct child to them
// to prevent unwanted side effects
// (For example, <template> may output more than one root element so you should 
// not use a <template> as a direct child for <no-ssr>
<template>
  <div>
    <no-ssr placeholder="A beautiful slider will be here after client-side hydration">
      <div>
        <carousel>
          <slide v-for="(slide, index) in maBeautifulSlides">
            <div class="ma-slide"> ... </div>
          </slide>
        </carousel>
      </div>
    </no-ssr>
  </div>
</template>

<script>
export default {
  data () {
    maBeautifulSlides: [
      // ...
    ]
  }
}
</script>

With this you can start using <carousel /> and <slide /> components in your pages/components without importing anything, but strictly between <no-ssr></no-ssr> tags otherwise you will get errors again.

dappiu avatar Mar 20 '19 13:03 dappiu

I could solve it by using import { Carousel, Slide } from 'vue-carousel/src/index'- maybe this helps others, too. Reason seems to be that it tries to inject styles at the wrong time when using the default minified version

sebastianrothbucher avatar Aug 01 '19 13:08 sebastianrothbucher

@sebastianrothbucher this solved it for me too. On closer inspection of the webpack generated dist/vue-carousel.min.js it was referencing window early on in the code - and from searching around - this is a webpack behaviour? Anyhow referencing the src, seems to avoid the webpack dilemma and works nicely for SSR and client :)

moldedjelly avatar Aug 16 '19 03:08 moldedjelly

Same issue when building my gridsome site. Solution from @sebastianrothbucher does not work there

mklueh avatar Aug 29 '19 20:08 mklueh

There will be generated class VueCarousel-inner if you try to check the source then if you observed the element style of flex-basis is 0 and visibility hidden you can change that to example flex-basis: 425px;visibility: visible!important; through javascript although this not ssr anymore but still working and this works for me.

vokz avatar Feb 27 '20 03:02 vokz

The solution by user @jorgvm for this issue is what got it to render for me.

cobbie avatar Mar 02 '20 07:03 cobbie

Hey Fellas. Do we have any updates regarding SSR support and is the plugin going to be updated in general? I can see a lot of PRs opened but no new version since Apr 2019.

pmanikas avatar Mar 23 '20 19:03 pmanikas

there's nothing new yet but you can try the solution i made. just read my comment above

vokz avatar Mar 25 '20 06:03 vokz