Svelte Web Interfaces with Svelte
Published: 2019-09-06 21:09:15

Did anyone else just find out that svelte is a real word? It's pretty much a synonym for lithe or slender.

If you're watching the front-end JavaScript framework ecosystem closely these days, you've probably noticed that JavaScript has started to stabilize. We no longer see a dozen frameworks competing for market share in the JavaScript space. Now, we've got a handful of front-running frameworks and a few niche ones.

### Why would someone introduce a new component framework for building user interfaces with JavaScript?

Good question, I'm glad you asked.

Traditional JavaScript frameworks (React is like six years old, we can call that traditional, right?) put a heavy load on the browser even though they take advantage of a virtual DOM. A virtual DOM helps frameworks like React re-render your web interface upon state change performantly. It's an excellent idea.

But it might not be necessary.

### So what is wrong with the virtual DOM?

There is nothing wrong with the VDOM, usually. Relying on a virtual DOM is totally fine for most use cases; however, it is still overhead. 

There is [a top-notch article by Rich Harris](https://svelte.dev/blog/virtual-dom-is-pure-overhead) that covers how the Svelte project feels about the virtual DOM. To boil it down, a virtual DOM is fine in practice for many applications, but it is not faster than the DOM itself. 

An analogous example described in the above article is the C compiler. You *could* write faster code lower in the stack, but why would you when C is friendly (and therefore productive) and fast enough?

But what if you didn't have to pick between productivity and speed?

With Svelte, you can have the same powerful model you see in React and Vue, without the overhead of the virtual DOM.

### What makes Svelte special?

It removes overhead.

The hypothesis behind Svelte is straightforward: Browser-based UI frameworks result in a lot of overhead; it is possible to remove this overhead by handling the framework in a build step outside of the browser. Svelte doesn't have a virtual DOM.

It's a compiler, not a dependency.

Frameworks like Vue and React are dependencies; they interact with your code while it executes. Svelte is a compiler; it interacts with your code before you ever put that code in production — Svelte outputs vanilla JavaScript.

### How does it work?

There is some really awesome documentation on [svelte.dev](https://svelte.dev/), and I plan to write a series of tutorials on Svelte shortly. There is a wonderful [REPL available on the Svelte site](https://svelte.dev/repl/hello-world?version=3) too.

But, I'll share some code in this article to give you a taste of working in Svelte. You should use the REPL to follow along. 😉


```html
<!-- App.svelte -->

<script>
  let name = 'world';
</script>

<style>
  h1 {
    font-family: Helvetica;
    color: #333;
  }
</style>

<h1>Hello {name}!</h1>
```

That's weird. It looks like a generic HTML file with one exception:

```html
<h1>Hello {name}!</h1>
```

What's up with the curly brackets? Svelte makes it easy to drop JavaScript into your markup, just like JSX. For example, we could just as easily do this:

```html
<h1>Hello {name || 'world'}!</h1>
```

And just like that, we are handling falsey values for the `name` variable.

If you're following along, you might be confused because I called this a component framework (I'll probably use the words framework and compiler interchangeably, sorry). You'd be forgiven for asking where the component is, but you're looking at the component:

```html
<!-- App.svelte -->

<script>
  let name = 'Jacob';
</script>

<style>
  h1 {
    font-family: Helvetica;
    color: #333;
  }
</style>

<h1>Hello {name || 'world'}!</h1>
```

What if we want to add another component, we can just make a new file:

```html
<!-- Image.svelte -->

<script>
  export let src;
  export let alt;
</script>

<style>
  h1 {
    font-family: "Comic Sans MS";
    color: #ff0;
  }
</style>

<h1>Check this out!</h1>
<img {src} {alt}>
```

Now let's import our new component and render it in `App.svelte`.

```html
<!-- App.svelte -->

<script>
  import Image from './Image.svelte';
    
  let name = 'Jacob';
</script>

<style>
  h1 {
    font-family: Helvetica;
    color: #333;
  }
</style>

<h1>Hello {name || 'world'}!</h1>
<Image 
    src="https://ksassets.timeincuk.net/wp/uploads/sites/55/2016/04/2014RickAstley_Getty109255193201014-1.jpg"
    alt="The world's most talented musician"
/>
```

You might notice something really cool about the `<h1>` tags. The styles from `App.svelte` don't override the styles from `Image.svelte` and vice-versa. Styles are scoped to components 🤯.

That's cool and all, but keep in mind that this is a compiler. The code that I'm writing is code for humans (and Svelte allows for some human-friendly code), but we've got to run it through the compiler to get code for the browser.

This is what the browser sees:

CSS:
```CSS
h1.svelte-iq7gzg{font-family:Helvetica;color:#333}
```
and javascript:
```javascript
/* App.svelte generated by Svelte v3.9.2 */
import {
    SvelteComponent,
    append,
    attr,
    destroy_component,
    detach,
    element,
    init,
    insert,
    mount_component,
    noop,
    safe_not_equal,
    space,
    text,
    transition_in,
    transition_out
} from "svelte/internal";
import Image from "./Image.svelte";

function create_fragment(ctx) {
    var h1, t0, t1_value = name || 'world' + "", t1, t2, t3, current;

    var image = new Image({
        props: {
        src: "https://ksassets.timeincuk.net/wp/uploads/sites/55/2016/04/2014RickAstley_Getty109255193201014-1.jpg",
        alt: "The world's most talented musician"
    }
    });

    return {
        c() {
            h1 = element("h1");
            t0 = text("Hello ");
            t1 = text(t1_value);
            t2 = text("!");
            t3 = space();
            image.$$.fragment.c();
            attr(h1, "class", "svelte-iq7gzg");
        },

        m(target, anchor) {
            insert(target, h1, anchor);
            append(h1, t0);
            append(h1, t1);
            append(h1, t2);
            insert(target, t3, anchor);
            mount_component(image, target, anchor);
            current = true;
        },

        p: noop,

        i(local) {
            if (current) return;
            transition_in(image.$$.fragment, local);

            current = true;
        },

        o(local) {
            transition_out(image.$$.fragment, local);
            current = false;
        },

        d(detaching) {
            if (detaching) {
                detach(h1);
                detach(t3);
            }

            destroy_component(image, detaching);
        }
    };
}

let name = 'Jacob';

class App extends SvelteComponent {
    constructor(options) {
        super();
        init(this, options, null, create_fragment, safe_not_equal, []);
    }
}

export default App;
```

👆This is not code for humans. This is code for the browser; it is optimized for the browser. Separating the code for humans and the code for the machine means we don't have to choose between readability and speed.

Think of this like any compiler. The code that comes out of a compiler isn't intended for humans, it's intended for machines. The code that goes into the compiler _is_ intended for humans. As a lover of readable code, this excites me.

At a glance, Svelte is a tool for writing component-based UIs with incredibly simple (read: maintainable) JavaScript. I'm not sure I'd put it in production yet, but I'm more excited to follow the development of Svelte than almost any other web technology right now.

🚀🎸🏎

### There's more...

I'm writing [a lot of articles](https://jh.codes) these days, I run a [podcast](https://www.devpath.fm), and I've started sending out a [newsletter digest](https://pages.convertkit.com/674caf55d4/f30f7753a7) about all of the awesome stories I'm hearing.

You can also follow me on [Twitter](https://twitter.com/jakeherrington), where I make silly memes and talk about being a developer.