ES6.today Articles

Svelte3 Impressions

September 07, 2019

Wait? What is this? A new framework?? Yep, a new framework. Don’t get me wrong, I’m all-in on React’s rich ecosystem that encompasses the worlds of create-react-app, gatsby, NEXT, GraphQL (not really a React-specific technology), Redux (again, not a React-specific technology) and all of the other software development goodness that surrounds these things! However, I’ve heard rumblings of an interesting new framework called “Svelte3”. Wes Bos and Scott Tolinski checked it out on a recent episode of the Syntax.FM podcast, and they seemed pretty impressed. Some of what they were saying seemed really interesting, so I figured why not check it out for myself?

Initial Impression

So, as most software developers know, the initial experience with a new library or framework can be made or broken based on the intro documentation. Svelte3 has a nice interactive tutorial (read: “codepen style playgrounds”…) to get you started on the basics of how Svelte works. This was perfect as it allowed me to explore not only the tutorial step I was looking at, but anything I felt like trying. Break all the things!

So What is Different About Svelte?

Svelte3 does a lot of the stuff we wish other frameworks would do without jumping through all the hoops, or at least that’s my impression having run through a few pages of the tutorial. Everything seems more like plain CSS, plain old Javascript, and plain old HTML — but Svelte3 is providing some magic for us that makes this stuff work the way we wish it worked out of the box.

Comparing React and Svelte Components

Here’s a basic “Hello World” component in React:

HelloWorld.js (React):

const HelloWorld = () {
  return <div>Hello World!</div>
}

export default HelloWorld;

If you’re a React developer, you probably think that is one of the most simple components you’ll ever see, right?

Check it out in Svelte3…

HelloWorld.svelte (Svelte3):

<div>Hello World!</div>

Huh? That’s not a component?!?! Isn’t that just HTML? That’s what it looks like, but since Svelte3 is compiled to Javascript, it actually looks something like this… (There isn’t really a need to try and read/understand the following snippet as it’s the compiled JS output from the Svelte compiler)…

/* App.svelte generated by Svelte v3.9.2 */
import {
  SvelteComponent,
  detach,
  element,
  init,
  insert,
  noop,
  safe_not_equal,
} from 'svelte/internal'

function create_fragment(ctx) {
  var div

  return {
    c() {
      div = element('div')
      div.textContent = 'Hello World'
    },

    m(target, anchor) {
      insert(target, div, anchor)
    },

    p: noop,
    i: noop,
    o: noop,

    d(detaching) {
      if (detaching) {
        detach(div)
      }
    },
  }
}

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

export default App

Aha! That’s where it all happens!! A really cool thing about the Svelte interactive playground is that it shows you what your code is compiled to. That’s where the javascript block above came from. Kinda cool stuff.

What About Styling?

In React land, all the cool kids are using some sort of CSS-in-JS solution like Styled-Components or JSS and usually, the purpose is to help encapsulate the CSS into classes that won’t collide and/or overwrite each other in the DOM. This basic concept doesn’t come with React out of the box, so these third-party solutions are necessary.

Svelte3 has a styling system that automatically scopes your CSS to the HTML that is part of that component to prevent CSS leakage to other parts of your application. CSS’s cascading and encapsulation concepts can be kind of hard to understand for all but the most astute CSS users.

An example to show how CSS is handled in Svelte3

extending our HelloWorld example with styling…

<h3>Hello World!</h3>
<style>
  h3 {
    color: rebeccapurple;
    font-size: 2em;
  }
</style>

Again, this looks just like an HTML document, doesn’t it? When Svelte compiles this, we end up with a stylesheet that looks like this…

h3.svelte-eh7q0i {
  color: rebeccapurple;
  font-size: 2em;
}

I didn’t specify a class of .svelte-eh7q0i?!?!

Interesting! Our simple h3 style definition was transformed into a styled definition for a custom className that is unique to that component. So with this nice little tidbit of built-in awesome sauce we can safely write CSS (in standard notation, I might add!) in a Svelte component.

This doesn’t answer the question of how it handles themes and global styles, but this along is really nice. We’ll get into more details should I decide to continue exploring Svelte further in a later article. This is supposed to be “first-impressions” rather than a deep-dive comparison of Svelte to other frameworks. I digress…

What About Javascript??

It’s pretty much the same idea as the styling from the most basic standpoint. You simply use a script tag and write your Javascript inline in the component. You can use curly braces to execute and output variables and other javascript expressions. So again let’s take our HelloWorld.svelte project…

<script>
  const name = 'Robert'
</script>
<style>
  h3 {
    color: purple;
    font-size: 2em;
  }
</style>
<h3>Hello {name}!</h3>

Now, we have a component that has a custom javascript variable (i.e. ‘name’), that also has some custom css styling that is automatically scoped to the component (via the custom class that gets applied during compilation). The h3 in this component will be purple and 2em in size, but other h3’s outside this component will not.

Composition

Just as in a React app, you can import components from other files and compose them together by nesting them inside of each other, Svelte uses the same pattern. One of the major differences is that the component name is defined by the file name in Svelte, as opposed to being specified like you might with React.

So if we have the following svelte component files…

TodoListing.svelte, TodoEntry.svelte, TodoDisplay.svelte

We might have App.svelte as the container to compose these…much like we would import React component files…

<script>
  import TodoListing from './TodoListing.svelte'
  import TodoEntry from './TodoEntry.svelte'
  import TodoDisplay from './TodoDisplay.svelte'
</script>
<div>
  <TodoListing />
  <TodoEntry />
  <TodoDisplay />
</div>

Obviously, the above example would really need some additional layout work to display sensibly, but it currently shows simply importing multiple components into another, and putting them on the page. It reminds me an awful lot of React!

Reactivity

In the world of React, we ‘useState’ (hooks) or ‘setState’ (classes). These important pieces of data are considered the definition of the current state of the application. As I’ve heard elsewhere, UI is merely a function of state.

So I looked for this paradigm in Svelte. I was pleasantly surprised to find that variables are reactive! So let’s say for instance we have…

<script>
  let count = 0
  function incrementCount() {
    count += 1
  }
  function resetCount() {
    count = 0
  }
</script>
<h3>{count}</h3>
<button on:click="{incrementCount}">Increment</button>
<button on:click="{resetCount}">Reset</button>

That is one way to write the old counter example. Yep, you actually mutate the variable, and where it is used updates to the new value. It’s that simple. Cool.

Reactive Declarations

WHOA! Hold the phone!! These look and work a lot like React Hooks in that they will only update the derived value if one of the input variables change. This also reminds me of calculating some derived state from multiple pieces of state in a redux store by using Reselect selectors.

check out this example using Reactive Declarations…

<script>
  let count = 0
  $: doubled = count * 2
  $: tripled = count * 3
  $: quadrupled = count * 4

  function handleClick() {
    count += 1
  }
</script>
<p>{count} doubled is {doubled}, tripled {tripled}, quadrupled {quadrupled}</p>

Granted, in the above reactive declarations, there is only one input “count”. So of course, every time count is incremented, the derived value in teh reactive declaration will update.

This is cool stuff!

Properties (aka “props”)

Yep, Svelte has props also. They’re not exactly like I’m used to in React, but they’re close. There is some strange import and export syntax involved to pass props to nested components. Props can have default values, which is added to the strange import/export syntax.

DangerouslySetInnerHTML?

{@html ...} in Svelte land is basically equivalent to dangerouslySetInnerHTML= in React land. Svelte’s documentation makes sure to point out that there is no sanitization happening prior to inserting into the DOM, so as developers we need to be extra careful when outputting HTML in this manner as it can open the door for script injection attacks. Definitely not something we want.

<script>
  let string = `this string contains some <strong>HTML!!!</strong>`
</script>

<p>{@html string}</p>

outputs…

this string contains some **HTML!!!**

Finally, Templates?

There’s no JSX out of the box, so how do I go about returning a list from an array? Svelte handles this with conditionally rendered markup. So for instance, let’s consider that we have a Login Button that should toggle with a value…

<script>
  let user = { loggedIn: false }

  function toggle() {
    user.loggedIn = !user.loggedIn
  }
</script>

{#if user.loggedIn} 
  <button on:click="{toggle}">Log out</button> 
{/if} 
{#if !user.loggedIn} 
  <button on:click="{toggle}">Log in</button> 
{/if}

Iteration:

<ul>
  {#each cats as cat}
  <li>
    <a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
      {cat.name}
    </a>
  </li>
  {/each}
</ul>

Well, there’s a lot more and I suppose I may write more about Svelte in the future. My initial evaluation is that it is a powerful framework that might be able to give a framework like React a run for it’s money! I am curious how Svelte holds up at scale. Clearly all of the examples in this article are quite elementary and have minimal complexity. At first glance, I see a lot of the same patterns that I might use to create a ReactJS application, without some of the.. ehem.. “boilerplate”.

Resources

Svelte-related links and resources (links open in a blank window)


All things JavaScript and Front-end Development :: Editor - Matt Howey