Search code examples
svelteswiper.jsvitecodesandboxsveltekit

Sveltekit: Cannot find module 'swiper'


I tried the sveltekit-swiper example from https://swiperjs.com/svelte

08:07:51 [vite] Error when evaluating SSR module /src/routes/s.svelte: Error: Cannot find module 'swiper' from 'C:/Svelte/tw09swipe/src/routes'
    at Function.resolveSync [as sync] (C:\Svelte\tw09swipe\node_modules\resolve\lib\sync.js:102:15)
    at resolveFrom$3 (C:\Svelte\tw09swipe\node_modules\vite\dist\node\chunks\dep-9f74b403.js:4081:29)
    at resolve (C:\Svelte\tw09swipe\node_modules\vite\dist\node\chunks\dep-9f74b403.js:75136:22)
    at nodeRequire (C:\Svelte\tw09swipe\node_modules\vite\dist\node\chunks\dep-9f74b403.js:75115:25)
    at ssrImport (C:\Svelte\tw09swipe\node_modules\vite\dist\node\chunks\dep-9f74b403.js:75057:20)
    at eval (/src/routes/s.svelte:7:37)
    at async instantiateModule (C:\Svelte\tw09swipe\node_modules\vite\dist\node\chunks\dep-9f74b403.js:75100:9)

I have installed new copies of sveltekit and swiper. Versions:

[email protected]
[email protected]
@sveltejs/[email protected]

A working example with Swiper 7 can be found in the codesandbox: https://codesandbox.io/s/3dxrg It uses Swiper 7.0.3 and SvelteKit v1.0.0-next.104


I have installed svelte/kit and swiper without any changes:

mkdir tw09swipe
cd tw09swipe
npm init svelte@next
npm install
npm i swiper

This is my package.json:

{
  "name": "~TODO~",
  "version": "0.0.1",
  "scripts": {
    "dev": "svelte-kit dev",
    "build": "svelte-kit build",
    "preview": "svelte-kit preview",
    "check": "svelte-check --tsconfig ./tsconfig.json",
    "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch"
  },
  "devDependencies": {
    "@sveltejs/kit": "next",
    "svelte": "^3.34.0",
    "svelte-check": "^2.0.0",
    "svelte-preprocess": "^4.9.4",
    "tslib": "^2.0.0",
    "typescript": "^4.0.0"
  },
  "type": "module",
  "dependencies": {
    "swiper": "^7.0.5"
  }
}

And here is tsconfig.json:

{
    "compilerOptions": {
        "moduleResolution": "node",
        "module": "es2020",
        "lib": ["es2020", "DOM"],
        "target": "es2019",
        /**
            svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
            to enforce using \`import type\` instead of \`import\` for Types.
            */
        "importsNotUsedAsValues": "error",
        "isolatedModules": true,
        "resolveJsonModule": true,
        /**
            To have warnings/errors of the Svelte compiler at the correct position,
            enable source maps by default.
            */
        "sourceMap": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "baseUrl": ".",
        "allowJs": true,
        "checkJs": true,
        "paths": {
            "$lib": ["src/lib"],
            "$lib/*": ["src/lib/*"]
        }
    },
    "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
}

And svelte.config.js:

import preprocess from 'svelte-preprocess';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    // Consult https://github.com/sveltejs/svelte-preprocess
    // for more information about preprocessors
    preprocess: preprocess(),

    kit: {
        // hydrate the <div id="svelte"> element in src/app.html
        target: '#svelte'
    }
};

export default config;

routes/s.svelte

<script>

    // Import Swiper Svelte components    
    import { Navigation, Pagination, Scrollbar, A11y } from "swiper";
    import { Swiper, SwiperSlide } from "swiper/svelte";    

    // Import Swiper styles
    import "swiper/css";
    import "swiper/css/navigation";
    import "swiper/css/pagination";
    import "swiper/css/scrollbar";
</script>

<Swiper
    modules={[Navigation, Pagination, Scrollbar, A11y]}
    spaceBetween={50}
    slidesPerView={3}
    navigation
    pagination={{ clickable: true }}
    scrollbar={{ draggable: true }}
    on:slideChange={() => console.log("slide change")}
    on:swiper={(e) => console.log(e.detail[0])}
>
    <SwiperSlide>Slide 1</SwiperSlide>
    <SwiperSlide>Slide 2</SwiperSlide>
    <SwiperSlide>Slide 3</SwiperSlide>
    <SwiperSlide>Slide 4</SwiperSlide>
    ...
</Swiper>

Solution

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