2
votes

Hello I am having an issue with Nuxts ssr. I a trying to add 'vue-slick' to my web app and no matter what I do it continues to show "window is not defined".

As you can see I have tried multiple ways to allow vue-slick to be loaded on client side. Using plugins didn't help, using process.client in my component did not work as well.

Components/Carousel/Carousel.vue

 <template>
<div class="carousel">
<Slick ref="slick" :options="slickOptions">
    <a href="http://placehold.it/320x120">
            <img src="http://placehold.it/320x120" alt="">
        </a>
        ...
    <a href="http://placehold.it/420x220">
            <img src="http://placehold.it/420x220" alt="">
        </a>


    </Slick>
</div>

</template>

<script>
if (process.client) {
  require('vue-slick')
}
import Slick from 'vue-slick'

export default {    

    components: {
        Slick
    },
    data() {
        return {

            slickOptions: {
                        slidesToShow: 4

            },

            isMounted: false
        }
    },

    methods: {

    }


}
</script>

nuxt.config.js

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

plugins/vue-slick

import Vue from 'vue'
import VueSlick from 'vue-slick'

Vue.use(VueSlick);

Thanks for any help you can give!

2

2 Answers

8
votes

So this is due to nuxt trying to render the slick component on the server side, even though you have set ssr: false in nuxt.config.

I have had this issue in other nuxt plugins and these steps should fix it.

in nuxt.config.js add this to your build object:

build: {
    extend(config, ctx) {
    if (ctx.isServer) {
        config.externals = [
          nodeExternals({
            whitelist: [/^vue-slick/]
          })
        ]
      }
    }
  }

and in the page where you are trying to serve it you have to not mount the component until the page is fully mounted. So in your Components/Carousel/Carousel.vue set it up like this:

<template>
  <div class="carousel">
    <component
      :is="slickComp"
      ref="slick" 
      :options="slickOptions"
    >
      <a href="http://placehold.it/320x120">
        <img src="http://placehold.it/320x120" alt="">
      </a>
        ...
      <a href="http://placehold.it/420x220">
        <img src="http://placehold.it/420x220" alt="">
      </a>
    </component>
  </div>
</template>

Then in your script section import your component and declare it like this:

<script> 
  export default {
    data: () => ({
        'slickComp': '',
    }),
    components: {
        Slick: () => import('vue-slick')
    },
    mounted: function () {
        this.$nextTick(function () {
           this.slickComp = 'Slick'
        })
    },
  }
</script>

Bascially this means the component isn't declared until the mounted function is called which is after all the server side rendering. And that should do it. Good luck.

1
votes

I found another simple solution. simply install "vue-slick" package to your nuxt project. $ yarn add vue-slick

then component markup like below.

<template>
    <component :is="slick" :options="slickOptions">
      <div>Test1</div>
      <div>Test2</div>
      <div>Test3</div>
    </component>
</template>

Finally set data and computed properties like this.

data() {
    return {
      slickOptions: {
        slidesToShow: 1,
        slidesToScroll: 1,
        infinite: true,
        centerMode: true,
      },
    };
  },
  computed: {
     slick() {
       return () => {
          if (process.client) {
          return import("vue-slick");
          }
        };
      },
    },

This solution prevents slick component importing globally as a plugin in nuxt config.