1

I am trying to implement a carousel in a Nuxt application. This is my package.json

 "dependencies": {
    "@nuxtjs/i18n": "^7.0.3",
    "core-js": "^3.15.1",
    "flickity": "^2.2.2",
    "lodash": "^4.17.21",
    "nuxt": "^2.15.7",
    "postcss-nesting": "^8.0.1",
    "throttle-debounce": "^3.0.1",
    "vue-flickity": "^1.2.1"
  },

This is my code

<template>
  <ClientOnly>
    <Flickity
      ref="flickity"
      :key="keyIncrementer"
      class="carousel"
      :class="{ 'carousel--active': active }"
      :options="computedOptions"
    >
      <slot />
    </Flickity>
  </ClientOnly>
</template>

<script>

import Flickity from 'vue-flickity'

const DEFAULT_OPTIONS = {
  cellAlign: 'left',
  pageDots: true,
  prevNextButtons: true
}
export default {
  components: {
    Flickity,
  },
  name: 'BaseCarousel',
  props: {
    active: {
      type: Boolean,
      default: true
    },
    options: {
      type: Object,
      required: false,
      default: () => ({})
    }
  },

If I don't comment out import Flickity from 'vue-flickity' and components: { Flickity, }, I get this error message.

error message

I can't understand what is wrong here. If someone knows please help...

kissu
  • 40,416
  • 14
  • 65
  • 133
Maxime
  • 337
  • 2
  • 17

3 Answers3

3

Another workaround is to locally register vue-flickity as an async component only on the client:

export default {
  components: {
    [process.browser && 'Flickity']: () => import('vue-flickity'),
  }
}

demo

tony19
  • 125,647
  • 18
  • 229
  • 307
2

Importing it as a plugin is a solution as shown here: https://github.com/drewjbartlett/vue-flickity/issues/38#issuecomment-906280271

Meanwhile, it is not optimal at all.
Importing it with a dynamic import may be a solution, I'm trying to find a way to write it properly.


Updated answer

This seems to work properly on my side, can you please confirm?

<template>
  <ClientOnly>
    <Flickity
      ref="flickity"
      :key="keyIncrementer"
      class="carousel"
      :class="{ 'carousel--active': active }"
      :options="computedOptions"
    >
      <slot />
    </Flickity>
  </ClientOnly>
</template>

<script>
import Vue from 'vue'

const DEFAULT_OPTIONS = {
  cellAlign: 'left',
  pageDots: true,
  prevNextButtons: true,
}

export default {
  name: 'BaseCarousel',
  props: {
    active: {
      type: Boolean,
      default: true,
    },
    options: {
      type: Object,
      required: false,
      default: () => ({}),
    },
  },
  async mounted() {
    if (process.browser) {
      const Flickity = await import('vue-flickity')
      Vue.component('Flickity', Flickity)
    }
  },
}
</script>
kissu
  • 40,416
  • 14
  • 65
  • 133
  • But now my console is telling me ` vue.runtime.esm.js?2b0e:619 [Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.` – Maxime Oct 14 '21 at 15:24
  • Did you removed the former `components` key? @Maxime – kissu Oct 14 '21 at 15:25
  • Yes I did, I commented it out – Maxime Oct 14 '21 at 15:27
  • @Maxime I don't have the same behavior. So I guess it's coming from somewhere else at this point. Could you update your code snippet with the whole up to date code that you have? – kissu Oct 14 '21 at 15:29
  • 1
    @kissu `Vue.component()` performs *global component registration*, so your updated suggestion has the same effect as the plugin (globally register `vue-flickity` on the client). – tony19 Oct 16 '21 at 07:18
2

Have you added to the plugins/vue-flickity.js something like:

import Vue from 'vue'
import Flickity from 'vue-flickity'

Vue.component('Flickity', Flickity)

?

Add also to the nuxt.config.js

plugins: [
  { src: '~/plugins/vue-flickity.js', ssr: false },
]
kissu
  • 40,416
  • 14
  • 65
  • 133
Jonathan
  • 10,936
  • 8
  • 64
  • 79
  • 1
    As I've said in my answer, even if this method works it has the huge con of bringing the whole thing to your entire app. Something that is not really worth it if you're using it only in one place. #performanceMatters – kissu Oct 14 '21 at 15:38