Search code examples
importconsolesvelteapexchartssveltekit

SvelteKit console error "window is not defined" when i import library


I would like to import apexChart library which using "window" property, and i get error in console.

[vite] Error when evaluating SSR module /src/routes/prehled.svelte:
ReferenceError: window is not defined

I tried use a apexCharts after mount, but the error did not disappear.

<script>
 import ApexCharts from 'apexcharts'
 import { onMount } from 'svelte'
 const myOptions = {...myOptions}
 onMount(() => {
   const chart = new ApexCharts(document.querySelector('[data-chart="profit"]'), myOptions)
   chart.render()
 })
</script>

I tried import a apexCharts when i am sure that browser exist.

 import { browser } from '$app/env'
 if (browser) {
   import ApexCharts from 'apexcharts'
 }

But i got error "'import' and 'export' may only appear at the top level"

I tried disable ssr in svelte.config.js

import adapter from '@sveltejs/adapter-static';
const config = {
    kit: {
        adapter: adapter(),
    prerender: {
      enabled: false
    },
    ssr: false,
}

I tried to create a component in which I import apexChart library and I created a condition that uses this component only if a browser exists

{ #if browser }
  <ProfitChart />
{ /if }

Nothing helped.

Does anyone know how to help me please?


Solution

  • The easiest way is to simply include apexcharts like a standalone library in your webpage like this:

    <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
    

    And then simply use it in the onMount:

    onMount(() => {
      const chart = new ApexCharts(container, options)
      chart.render()
    })
    

    You can add this line either in your app.html or include it where it's required with a <svelte:head> block.

    An alternative way would be to dynamically import during onMount:

    onMount(async () => {
      const ApexCharts = (await import('apexcharts')).default
      const chart = new ApexCharts(container, options)
      chart.render()
    })
    

    As an extra: use bind:this instead of document.querySelector to get DOM elements, that would be the more 'svelte' way.