Skip to content

Aquent | DEV6

Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages

Svelte 3 – Overview and First Impressions

Written by: Eugene Havrylov

Svelte is a new way of creating single page application with JavaScript. It’s been around for a couple of years and it’s considered as a pretty young framework. In this post we will go through the core Svelte features and the benefits for developers.

What is Svelte?

First of all, Svelte is not a next JavaScript framework. It is a compiler. That means, Svelte is not served with your code to a browser. Instead, it compiles your code during build time into a bundle that only contains your code and the Svelte features you used in your code. That sounds great, but what exactly does that give us?

The most important thing is a smaller bundle size. The smaller your JS bundle transferred over the network to a user, the faster the page loads and the better the user experience is. Here is a comparison of a React starter project with Svelte one. Both were built in production mode and served by the local network:

As you can see, the React page requires almost 42KB (bundle + chunk) to be presented and Svelte needs only 1.6KB. It’s a huge difference, especially for users that have a slower connection. This happens because React (one of the most lightweight frameworks so far) needs to be in the browser to manage virtual DOM rendering and all the logic behind it. However, Svelte has a static DOM and all required computations were made at build time. Here is how the creator of Svelte describes it:

“Svelte is a component framework — like React or Vue — but with an important difference. Traditional frameworks allow you to write declarative state-driven code, but there’s a penalty: the browser must do extra work to convert those declarative structures into DOM operations, using techniques like virtual DOM diffing that eat into your frame budget and tax the garbage collector.

Instead, Svelte runs at build time, converting your components into highly efficient imperative code that surgically updates the DOM. As a result, you’re able to write ambitious applications with excellent performance characteristics.”

Rich Harris

Another feature of Svelte is that every component has its own component-scoped styles. It won’t let you to accidentally change styles of elements that don’t belong to the component. This way, we have module-scoped styles out of the box. Also, Svelte allows you to declare global styles that can be used across your application. Moreover, all unused styles will be purged at build time.

Working with DOM

Svelte, as other frameworks, allows you to have conditional rendering or render list elements with a loop by using special blocks within your .svelte file:

<script>
   let x = 7;
</script>

{#if x > 10}
   <p>{x} is greater than 10</p>
{:else if 5 > x}
   <p>{x} is less than 5</p>
{:else}
   <p>{x} is between 5 and 10</p>
{/if}

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

You can loop over generic iterables with each […iterable].

Every web application has to deal with asynchronous data. If you need to display data from an async method that returns a promise you can use an await block directly in markup:

{#await promise}
   <p>...waiting</p>
{:then number}
   <p>The number is {number}</p>
{:catch error}
   <p style="color: red">{error.message}</p>
{/await}

I’ve seen this feature only in heavy frameworks like Angular.

Svelte uses Slots for component composition. Any component can have its children to be passed and rendered from parent component. We are not restricted by the number of slots we want to render in a children component. We just need to specify what slot a part of the DOM refers to:

<ContactCard>
   <span slot="name">
      P. Sherman
   </span>

   <span slot="address">
      42 Wallaby Way<br>
      Sydney
   </span>
</ContactCard>

And the ContactCard.svelte component:

<article class="contact-card">
   <h2>
      <slot name="name">
         <span class="missing">Unknown name</span>
      </slot>
   </h2>

   <div class="address">
      <slot name="address">
         <span class="missing">Unknown address</span>
      </slot>
   </div>
</article>

As you can see from this example, we can specify the default content of a slot if no children were passed.

All these techniques give us valuable flexibility and allow us to develop components in a clean and understandable way.

Svelte’s reactivity

Svelte is very different from other frameworks by its built-in reactivity. For instance, React recently implemented a similar pattern with hooks. Developers of Svelte wanted to reduce boilerplate code that is caused by hooks and make it clear and simple to trigger updates on value changes. Svelte automatically updates the DOM when your component’s state changes.

When we need a part of a component state to be computed from another part of the state and recomputed whenever it’s changed, we can use one of the Svelte operators to observe a value change and to trigger some events / methods:

<script>
   let count = 0;
   $: doubled = count * 2;

   function handleClick() {
      count += 1;
   }
</script>

<button on:click={handleClick}>
   Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

<p>{count} doubled is {doubled}</p>

When a count variable changes we listen to its changes with the $: operator and set a new value to the “doubled” variable. We are not limited here to declaring values. We can also run arbitrary statements and group them together in a block:

$: {
   console.log(`the count is ${count}`);
   alert(`I SAID THE COUNT IS ${count}`);
}

We can even put a statement within a condition to determine if we need to trigger it based on an observable value:

$: if (count >= 10) {
...
}
 

The downside of this approach is that Svelte cannot recognise array methods like push or splice. That happens because the changed array keeps the same reference in memory. However, there is a workaround with es6 syntax:

function addNumber() {
   numbers = [...numbers, numbers.length + 1];
}

In this case an array gets a new reference and triggers an updated function.

Overall, this feature is really impressive. It reduces tons of boilerplate code and helps us to keep every component file clean and light.

State management

The reactivity concept allows us to waive Local State management because everything we talked about in a previous section is applied to the local state. Despite the fact that Svelte is a lightweight approach to develop SPAs it comes with a way to do global state management.

A store is simply an object with a subscribe method that allows interested parties to be notified whenever the store value changes. Svelte Core library has different stores to implement state management across the whole application:

  • Writable Store – function that creates a store which has values that can be set from ‘outside’ components. It gets created as an object with additional set and update methods.
  • Readable Store – creates a store whose value cannot be set from ‘outside’, the first argument is the store’s initial value.
  • Derived Store – derives a store from one or more other stores. Whenever those dependencies change, the callback runs.

All these stores give us an out-of-the box approach to manage application state with no need to bring over any third-party library.

Sapper and other valuable features

Svelte has built in Dynamic and Recursive Components that allow you to write less code and reuse your components even more. Also, there is a pretty powerful animation library. We have a lot of different transition types, motions and animations from scratch. Remember, Svelte only bundles things we use in our code, so it’s good to have that kind of a swiss-army knife close by even though you might not use it.

Most of our applications require Routing. Svelte doesn’t have anything to manage that since it’s a compiler. However, a team that developed Svelte created Sapper:

Sapper is a framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing.

https://sapper.svelte.dev/

Sapper manages not only application routing but a server-side rendering, search engine optimisations, pre-fetching data and much more. Everything is made in a Svelte-like manner, so we have a very lightweight framework that allows you to build SSR Apps as well as Static content websites that can be useful for JAM Stack applications.

Wrap up

Svelte uses really impressive and modern approaches and has tons of useful features that come in handy for every developer. The main advantage of this framework is that it delivers a small bundle, so your web application can be used everywhere with an advanced user experience. Creators of Svelte highlight that Svelte is already used on devices that are limited by performance and in networks with a low bandwidth. I will definitely use Svelte for my next JAM Stack project because of its flexibility and the wide range of tools it offers to develop applications that look and feel native. The infrastructure of Svelte is not as developed as React or Angular is, but it’s just a matter of time and effort. Moreover, we can now use NativeScript with Svelte support to create cross platform mobile apps! Svelte is a good asset to have in every developer’s toolbox.