Reputation: 341
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>
Upvotes: 21
Views: 32928
Reputation: 599
{@html '<script src="/js/pages/projects.js" />'}
Can be use for SvelteKit as well.
Upvotes: 1
Reputation: 1261
// 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>
Upvotes: 10
Reputation: 1065
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
template.html
inside <head>
like <script src="http://localhost:8080/auth/js/keycloak.js"></script>
login.svelte
route used the onMount
which runs after the component is first rendered to the DOM
Works exactly as expected.
Upvotes: 4
Reputation: 843
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.
Upvotes: 30
Reputation: 29585
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.
Upvotes: 18