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>
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.
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.
Sapper is a framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With