Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swiper Svelte doesn't support SSR under Sapper JS #3961

Closed
1 of 2 tasks
igolkotek opened this issue Nov 20, 2020 · 18 comments · Fixed by #4061
Closed
1 of 2 tasks

Swiper Svelte doesn't support SSR under Sapper JS #3961

igolkotek opened this issue Nov 20, 2020 · 18 comments · Fixed by #4061

Comments

@igolkotek
Copy link

This is a (multiple allowed):

  • [] bug

  • enhancement

  • feature-discussion (RFC)

  • Swiper Version: 6.3.5.

  • Platform/Target and Browser Versions: Ubuntu 20.04, Firefox 83.

What you did

Sapper bundle compilation in dev mode fails both whether Swiper is added according to Swiper site example or with Mount according to Sapper recommendations.

@btakita
Copy link

btakita commented Dec 8, 2020

Would it be possible to include the source *.svelte components in the build? This would enable the *.svelte components to be built using the current project's svelte compiler, ensuring the correct version & configuration is used during the build.

@vltansky
Copy link
Collaborator

@igolkotek @btakita can you confirm that it's fixed ?

@silllli
Copy link

silllli commented Dec 14, 2020

Same problem here.

When I import the *.svelte components directly, Rollup fails to import some helper files like ./init-swiper and ./utils, or am I missing something?

@zakkor
Copy link

zakkor commented Dec 17, 2020

I've managed to fix it in a fork just enough so we can keep using Swiper in our project, however I'm not sure what a proper fix would be because I'm not familiar with the build process (which seems fairly complex).

It seems like the main issue is that when you import something in a Svelte project, it expects to compile the component along with all of its dependencies, through each projects' build process.
In this repository however, none of the built JS files that the Svelte components are trying to import are actually included, so Svelte complains that it can't find the files and the build doesn't work.

Here are the changes I made in order to get it to work: zakkor@0984204

I fixed the import paths so they point to the correct files, and included some of the needed pre-built JS files in the build dir (esm version only)

@vltansky
Copy link
Collaborator

@zakkor could you take a look at the suggested change in #4061 PR? I think this should work well.

@silllli
Copy link

silllli commented Feb 23, 2021

For anyone wondering: this works now, but you need to load the Swiper module dynamically in the onMount function. There is an example in the Sapper docs.

@brian-hay
Copy link

brian-hay commented Apr 4, 2021

@silllli any chance you can provide a working code snippet? I managed to get the imports working using onMount, and the first slide displays with left/right carets overlaid but empty pagination tag and navigation isn't possible - it's just stuck on first slide, with no console errors.

@silllli
Copy link

silllli commented Apr 4, 2021

Maybe you forgot to import and tell Swiper about the navigation and pagination modules?

I didn’t test it, but something like this should work:

<script>
  import { onMount } from 'svelte';
  import SwiperCore, { Navigation, Pagination } from 'swiper';

  // tell swiper to use navigation and pagination modules
  SwiperCore.use([Navigation, Pagination]);

  let Swiper;
  let SwiperSlide;

  onMount(async () => {
    // dynamically import swiper module
    const SwiperSvelteModule = await import('swiper/svelte');
    Swiper = SwiperSvelteModule.Swiper;
    SwiperSlide = SwiperSvelteModule.SwiperSlide;
  });
</script>

// NOTE: the swiper stylesheets need to be imported as well

<svelte:component
  this={Swiper}
  navigation={{
    nextEl: '.swiper-button-next',
    prevEl: '.swiper-button-prev',
  }}
  pagination={{
    el: '.swiper-pagination',
    type: 'bullets',
    clickable: true,
  }}>

  <svelte:component this={SwiperSlide}>
    Slide content
  </svelte:component>

  <div class="swiper-pagination" slot="container-end"></div>

  <div class="swiper-button-prev" slot="container-end"></div>
  <div class="swiper-button-next" slot="container-end"></div>
</svelte:component>

You also need to import the needed Swiper stylesheets. I do it in the style tag via SASS, whereas the Swiper docs import them in the <script> tag.

I hope it helps!

@brian-hay
Copy link

Thanks for the the comprehensive response @silllli . I had most of that in place but I modified to match exactly and no change as yet. I'll keep trying.

@silllli
Copy link

silllli commented Apr 4, 2021

I looked at it again since this bugged me. 🤓

Some adjustments were needed—I experienced a similar scenario that you describe (being stuck on the first slide) after running my code. I then added the slidesPerView param, and it worked! Maybe adding it will already do the trick for you.

Here is my actually working code:

<script>
  import { onMount } from 'svelte';
  import SwiperCore, { Navigation, Pagination } from 'swiper';

  // tell swiper to use navigation and pagination modules
  SwiperCore.use([Navigation, Pagination]);

  let Swiper;
  let SwiperSlide;

  onMount(async () => {
    // dynamically import swiper module
    const SwiperSvelteModule = await import('swiper/svelte');
    Swiper = SwiperSvelteModule.Swiper;
    SwiperSlide = SwiperSvelteModule.SwiperSlide;
  });
</script>

<style lang="scss">
  :global {
    @import 'swiper/swiper';
    @import 'swiper/components/navigation/navigation';
    @import 'swiper/components/pagination/pagination';

    .swiper-slide {
      height: 500px;
      background: red;
    }
  }
</style>

<svelte:component
  this={Swiper}
  navigation={true}
  pagination={{
    type: 'bullets',
    clickable: true,
  }}
  slidesPerView={1}
  spaceBetween={100}>

  <svelte:component this={SwiperSlide}>
    Slide content 1
  </svelte:component>

  <svelte:component this={SwiperSlide}>
    Slide content 2
  </svelte:component>

  <svelte:component this={SwiperSlide}>
    Slide content 3
  </svelte:component>
</svelte:component>

I also found this in the docs:

Note, Swiper Svelte component will create required elements for Navigation, Pagination and Scrollbar if you pass these params without specifying its elements (e.g. without navigation.nextEl, pagination.el, etc.)

So we actually don’t need to use the slots (and my first code was wrong—there can always only be one element assigned per slot).

@brian-hay
Copy link

Thanks @silllli . Still no joy for me. Not sure what's wrong with it.

I copied and pasted the carousel from https://github.com/beyonk-adventures/svelte-carousel/blob/master/src/Carousel.svelte into my own Carousel component and that worked.

nolimits4web added a commit that referenced this issue Apr 5, 2021
@nolimits4web
Copy link
Owner

https://swiperjs.com/svelte#using-with-sapper

@brian-hay
Copy link

@nolimits4web thanks for this but still having trouble. I'm using SvelteKit (beta), the replacement for Sapper.

After updating swiper dependencies and imports as per new docs, the production build runs but the the carousel doesn't work (all slides are displayed at once).

The local dev build results in the following error:
image

@thebells1111
Copy link

@brian-hay
Copy link

@thebells1111 yes that error I posted above is after following the instructions in that link.

@davidmgrana
Copy link

any news on this? having the same issue with sveltekit, navigation won't work

@RomanistHere
Copy link

RomanistHere commented Sep 22, 2021

There is a workaround for SvelteKit (should work for Sapper too)

Slider.svelte

<script>
    import { Swiper, SwiperSlide } from 'swiper/svelte';
    import SwiperCore, { Mousewheel, Pagination } from 'swiper';
    import 'swiper/css';
    import 'swiper/css/pagination';

    ...

    SwiperCore.use([Mousewheel, Pagination]);
</script>

...
    <Swiper
        direction='vertical'
        mousewheel={true}
        pagination={true}
        slidesPerView={1}
        on:slideChange={onSlideChange}
        on:swiper={(e) => console.log(e.detail[0])}
    >
        <SwiperSlide>
    </Swiper>
...

This is going work, we import Slider.svelte component this way:

<script>
    ...
    let Slider;
    onMount(async () => {
	    const module = await import('./components/Slider.svelte');
	    Slider = module.default;
    });
    ...
</script>

<svelte:component this={Slider}/>

...

So I basically suggest not to import all the Swiper instances within onMount, rather to import component, containing the Swiper Slider inside onMount - hope it's gonna help someone and keep your codebase cleaner :)

@xpluscal
Copy link

@RomanistHere excuse my ignorance, but how does this work for Sapper applications?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.