SSENSE / vue-carousel

A flexible, responsive, touch-friendly carousel for Vue.js
https://ssense.github.io/vue-carousel/
MIT License
1.72k stars 504 forks source link

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

Open midlantica opened 7 years ago

midlantica commented 7 years ago

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

--->

at components/CarouselShow.vue at pages/index.vue at .nuxt/components/nuxt.vue at layouts/default.vue ` 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.
ckpiggy commented 7 years ago

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)

midlantica commented 7 years ago

Thank you! 😭

KaronAmI commented 7 years ago

Nice! 😭

matthew-dean commented 7 years ago

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

mayognaise commented 7 years ago

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!! 🍙

SarasArya commented 7 years ago

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.

adyontech commented 7 years ago

@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?

SarasArya commented 7 years ago

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>
iloginow commented 6 years ago

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.

wesssel commented 6 years ago

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')
kingflamez commented 6 years ago

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

terryds commented 6 years ago

No update?

quinnlangille commented 6 years ago

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

terryds commented 6 years ago

@quinnlangille it's working without SSR

Defite commented 6 years ago

@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.

heshamelmasry77 commented 6 years ago

any solution for this problem

quinnlangille commented 6 years ago

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

dappiu commented 6 years ago

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)```
Defite commented 6 years ago

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.

podlebar commented 5 years ago

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

mix of dynamic import and mounted hook...

matthew-inamdar commented 5 years ago

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

dappiu commented 5 years ago

I can confirm the @podlebar solution is working with Nuxt@2.4.5 and vue-carousel@0.17.0, 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 commented 5 years ago
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.

sebastianrothbucher commented 5 years ago

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

moldedjelly commented 5 years ago

@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 :)

mklueh commented 5 years ago

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

vokz commented 4 years ago

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.

cobbie commented 4 years ago

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

pmanikas commented 4 years ago

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.

vokz commented 4 years ago

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

pmanikas commented 4 years ago

@vokz vue-carousel works in general. Problem is SSR. Although you've suggested a good and resourceful solution TBH. Following the title itself and the feature request, I'm referring to the ability to render data so that bots from search engines can read them. After all, that's what Nuxt.js and SSR is for.

educkf commented 4 years ago

I found another issue while using this component with Nuxt.js, that it looks like to add some kind of Memory Leak to the application server. I tried loading it only on client side, jumping any load on server and everything related to SSR, but it kept increasing memory usage on server. And as soon I removed it from dependencies, the Memory Leak stoped totally.

I don't know if it was my implementation, I have done it pretty vanilla, with only basic features. So for a proper Nuxt module, it would be good to review it more deeply for this kind of issue. setInterval and stuff like that that dont fit with Nuxt.js

NomNes commented 4 years ago

I can help, wait for PR)

NomNes commented 4 years ago

even using the Vue-cli for the build does not allow to automatically import styles during ssr. I see the only way out now is to extract the styles

or just import the src/*.vue to nuxt directly

arnabsen1729 commented 4 years ago

This https://github.com/SSENSE/vue-carousel/issues/81#issuecomment-363663139 worked for me and solved the issue of 'window' not defined

jambonn commented 4 years ago

@arnabsen1729 You can try this package https://www.npmjs.com/package/@jambonn/vue-concise-carousel

ekohadim commented 2 years ago

Thanks @wesssel your solution works for me without using no-ssr. Anyone who still has an issue with SSR try his solution. It didn't look promising at a second, but it works.