John Slegers
John Slegers

Reputation: 47081

Unable to import one Svelte component into another

I've been really intrigued by Svelte when I went through the documentation yesterday, but I'm struggling to set up even a pretty basic project and I can't seem to figure out what I'm doing wrong.

I'm starting out with the following HTML :

<!doctype html>
<html>
<head>
  <title>My first Svelte app</title>
</head>
<body>
  <main></main>
  <script src='App.js'></script>
  <script>
    const application = new App({
      target: document.querySelector( 'main' ),
      data: {
        name: 'world'
      }
    });
  </script>
</body>
</html>

Then, I create the following App.html component :

<div class="app">Hello {{name}}</div>
<div class="lines"></div>
<script>
  export default {}
</script>

I run svelte compile --format iife App.html > App.js, and everything works fine.

So far, so good!

Now, I create a Line.html component with the following content :

<div class="line">{{value}}</div>
<script>
  export default {}
</script>

I modify my App.html component like this :

<div class="app">Hello {{name}}</div>
<div class="lines"></div>
<script>
  import Line from './Line.html';

  export default {
    oncreate() {
      const line = new Line({
        target: document.querySelector( 'lines' ),
        data: {
          value: 'test'
        }
      });
    }
  }
</script>

I would expect this code to add something like <div class="line">test</div> to the DOM as a child of <div class="lines"></div>.

However, I get the following warning when I compile this code :

No name was supplied for imported module './Line.html'. 
Guessing 'Line', but you should use options.globals

And when I try to run the compiled code, I just get the following output in my console :

App.js:250 Uncaught ReferenceError: Line is not defined          at App.js:250
index.html:10 Uncaught TypeError: App is not a constructor       at index.html:10

What am I doing wrong here?


Note

I also raised this issue on Github.

Upvotes: 1

Views: 1594

Answers (1)

Rich Harris
Rich Harris

Reputation: 29585

Copying the answer from GitHub:

svelte-cli works on individual files — you would need to compile Line.html separately, and include it on the page like so:

<!doctype html>
<html>
<head>
  <title>My first Svelte app</title>
</head>
<body>
  <main></main>
  <script src='Line.js'></script> <!-- one for each component! -->
  <script src='App.js'></script>
  <script>
    const application = new App({
      target: document.querySelector( 'main' ),
      data: {
        name: 'world'
      }
    });
  </script>
</body>
</html>

It will guess that Line.js is defining a global variable called Line, which is how App.js is able to reference it — but it prefers that you're explicit about that, by using the --globals option.

Needless to say, this is a huge pain — it doesn't scale at all past a certain point. For that reason we recommend that you use a build tool with Svelte integrated. That way, you don't have to worry about juggling all the different imported files, and as a bonus Svelte is able to generate more compact code (because it can deduplicate some helper functions between components).

The easiest way to get started — and I keep meaning to write a very short blog post about this — is to click the 'download' button in the REPL. That will give you a basic project setup that you can get running with npm run dev and npm start. Under the hood it uses Rollup to create a bundle that can run in the browser.

Here's your test app running in the REPL. Notice that the way we use the <Line> component is by declaring it using components, and just writing it into the template, rather than manually instantiating it with oncreate.

Upvotes: 3

Related Questions