Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 421
LukasGur Avatar asked Jan 25 '26 23:01

LukasGur


2 Answers

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.

like image 68
Stephane Vanraes Avatar answered Jan 28 '26 20:01

Stephane Vanraes


I have found the last option with the Vite plugin to work best with less code in the end but will lose intellisense in vscode and see import highlighted as error (temp workaround at end): https://kit.svelte.dev/faq#how-do-i-use-x-with-sveltekit-how-do-i-use-a-client-side-only-library-that-depends-on-document-or-window

  1. Install vite plugin: npm i -D vite-plugin-iso-import
  2. Add plugin to svelte.config.js:
       kit: {
          vite: {
            plugins: [
                isoImport(),
            ],
  1. Add plugin to TypeScript config (if you use TS):
"compilerOptions": {
    "plugins": [{ "name": "vite-plugin-iso-import" }],
  1. Use as normal but note the "?client" on the import:
<script context="module">
    import { chart } from 'svelte-apexcharts?client';
    import { onMount } from 'svelte'
    let myOptions = {...myOptions}
    onMount(() => {
        myOptions = {...updated options/data}
    });
</script>

<div use:chart={myOptions} />

Debugging note: To have import not highlighting as an error temporarily, just:

  1. npm run dev, your project will compile fine, then test in browser to execute at least once.
  2. remove ?client now, save and continue debugging as usual.
like image 42
AEQ Avatar answered Jan 28 '26 20:01

AEQ