Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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>
like image 661
Joachim Morken Avatar asked Jan 07 '20 14:01

Joachim Morken


People also ask

What is more appropriate way to include JavaScript as an external file?

Create external JavaScript file with the extension . js. After creating, add it to the HTML file in the script tag. The src attribute is used to include that external JavaScript file.

What is an external JavaScript library?

All JavaScript libraries consists of two parts: The external JavaScript itself, which is simply a text file with the containing JavaScript code, saved as a . js file. A <script> tag referencing the external JavaScript file and defined on the page(s) that uses the library.

What is Sapper svelte?

Sapper is a framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing.


2 Answers

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.

like image 174
blindfish Avatar answered Nov 06 '22 17:11

blindfish


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.

like image 43
Rich Harris Avatar answered Nov 06 '22 18:11

Rich Harris