简体   繁体   中英

How do I load an external JS library in Svelte/Sapper?

I have been trying to load the ace editor ( https://ace.c9.io/ ) into my Sapper application. I had success loading it in the script tag when I loaded it in a Sapper route, but when I am trying to do the same in a Svelte component which is again rendered by a route I get the error:

ace is not defined

This is the code I have, which is working fine if it is a Sapper route:

<div id="editor"> def main():
    return sum(range(1,100))
</div>

    <script src="https://pagecdn.io/lib/ace/1.4.6/ace.js" type="text/javascript" charset="utf-8"></script>

    <script>
          var editor = ace.edit("editor");
          editor.setTheme("ace/theme/monokai");
          editor.session.setMode("ace/mode/python");
          editor.resize()
    </script>

I hacked together a component to load external legacy JS libraries when I first started playing with Svelte2 and just refactored it to Svelte 3.

// LibLoader.svelte

<svelte:head>
  <script bind:this={script} src={url} />
</svelte:head>

<script>
  import { onMount, createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();
  export let url;
  let script;

  onMount(async () => {
    script.addEventListener('load', () => {
      dispatch('loaded');
    })

    script.addEventListener('error', (event) => {
      console.error("something went wrong", event);
      dispatch('error');
    });
  });
</script>
// MyComponent.svelte

<LibLoader url="myExternalLib.js"
on:loaded="{onLoaded}" />


<script>
  import LibLoader from './LibLoader.svelte';


  function onLoaded() {
    myExternalLib.doStuff();
  }
</script>

This is not thoroughly tested and for a one-off probably doesn't warrant a separate component; but basically the approach gets round the timing issue Rich Harris mentions. These days import is obviously the better option if it is available.

The way to use an external library in Svelte is to import it. I don't know how easy it is to do that with Ace — code editors tend to be somewhat complex, with their own module systems for loading languages and themes etc — but in theory it would look something like this:

<script>
  import ace from 'ace';
  import { onMount } from 'svelte';

  let div;
  let editor;

  onMount(() => {
    // we need to use onMount because the div hasn't
    // been created by the time the init code runs
    editor = ace.edit(div);
    editor.setTheme("ace/theme/monokai");
    editor.session.setMode("ace/mode/python");
    editor.resize();

    return () => {
      // any cleanup code goes here
    };
  });
</script>

<div bind:this={div}> def main():
    return sum(range(1,100))
</div>

If importing fails, you can always do it the old-fashioned way, adding the <script src="..."> tag to your main template.html , and continuing to use ace as a global. <script src="..."> tags inside Svelte components will load asynchronously — in other words, your component's code will generally run before the external script has loaded.

I needed to add the Keycloak Javascript adapter . The older answer here ( https://stackoverflow.com/a/61979865/2013924 ) did not work for me so I simply

  1. included the Keycloak script first in the template.html inside <head> like <script src="http://localhost:8080/auth/js/keycloak.js"></script>
  2. and then inside my login.svelte route used the onMount

which runs after the component is first rendered to the DOM

Works exactly as expected.

// document.js

export function loadScript(src) {
    return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = src;

        document.body.appendChild(script);

        script.addEventListener('load', () => resolve(script));
        script.addEventListener('error', () => reject(script));
    });
}

And then on the svelte component

// index.svelte
<script>
    import { onMount } from 'svelte';
    import { loadScript } from './document.js';

    onMount(async () => {
      await loadScript('your-external-script.js');
      console.log('script loaded successfully!');
    };
</script>
{@html '<script src="/js/pages/projects.js" />'}

Can be use for SvelteKit as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM