简体   繁体   English

如何在 Svelte/Sapper 中加载外部 JS 库?

[英]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.我一直在尝试将 ace 编辑器 ( https://ace.c9.io/ ) 加载到我的 Sapper 应用程序中。 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:当我在 Sapper 路由中加载它时,我成功地将它加载到脚本标签中,但是当我尝试在 Svelte 组件中执行相同操作时,该组件再次由路由呈现,我收到错误消息:

ace is not defined ace 未定义

This is the code I have, which is working fine if it is a Sapper route:这是我的代码,如果它是 Sapper 路由,它可以正常工作:

<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.当我第一次开始使用 Svelte2 时,我编写了一个组件来加载外部遗留 JS 库,然后将其重构为 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.但基本上这种方法解决了 Rich Harris 提到的时间问题。 These days import is obviously the better option if it is available.如果可以的话,现在import显然是更好的选择。

The way to use an external library in Svelte is to import it.在 Svelte 中使用外部库的方法是import它。 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="...">标签添加到你的主template.html ,并继续使用ace作为全局。 <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. Svelte 组件内的<script src="...">标签将异步加载 — 换句话说,您的组件代码通常会在外部脚本加载之前运行。

I needed to add the Keycloak Javascript adapter .我需要添加Keycloak Javascript 适配器 The older answer here ( https://stackoverflow.com/a/61979865/2013924 ) did not work for me so I simply这里的旧答案( https://stackoverflow.com/a/61979865/2013924 )对我不起作用,所以我只是

  1. included the Keycloak script first in the template.html inside <head> like <script src="http://localhost:8080/auth/js/keycloak.js"></script>首先将 Keycloak 脚本包含在<head>内的template.html例如<script src="http://localhost:8080/auth/js/keycloak.js"></script>
  2. and then inside my login.svelte route used the onMount然后在我的login.svelte路由中使用了onMount

which runs after the component is first rendered to the DOM在组件第一次渲染到 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.也可以用于 SvelteKit。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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