November 30, 2019
6 verses of Svelte haiku
Svelte 3.0 came out just a couple of months ago and received a lot of attention from the JS community. It got me interested in exploring the technology and I ended up doing a lightning talk on it at my company during our bi-weekly knowledge sharing session, the XKE.
To structure the talk I’ve written a 6 verse haiku, each verse represents a feature of Svelte during my research. Happy to share this with you today.
Svelte Haiku
Elegant and slender
Compilation in its nature
One word, reactive
Share state simply
No VDOM, yes performance
Use for joy.
Let's go through this haiku line by line and look into some of the features of Svelte.
Elegant and slender
A quick search on the definition of Svelte returns the following:
It is very fitting when you look at the API design. The creators managed to make the written code light and concise.
Here’s an example of a Svelte component:
// Counter.svelte
<script>
let count = 0;
function increment() {
count = count + 1;
}
</script>
<style>
button {
border: none;
}
</style>
<button on:click={increment}>
clicked {count} times
</button>
The .svelte
file consists of three blocks:
<script>
block with JS<style>
block with scoped CSShtml
template with Svelte bindings
In this example we’ve declared a count
variable. By declaring the variable it is made available in the html template. Incrementing the count
is as simple as reassigning the count
variable to a new value. The UI updates whenever a new value is assigned to a variable.
This api is made possible because Svelte operates on compilation step, where most JS frameworks do their work during run time.
This essential difference gives Svelte creators more flexibility in their API design, allowing them to create a concise and easy to understand API.
Compilation in its nature
At its core Svelte is a compiler. It turns .svelte
components into .js
files which a module bundler can then bundle together and include in the DOM.
Here’s a high level diagram on how this works:
Being a compiler gives Svelte a number of advantages, mainly:
API design flexibility
Svelte API designers have more flexibility in designing a simple to use API for its users without sacrifising performance
Minimal size
Any unused modules can be tree shaken; leaving the minimum required amount of code to make it run. For example, if you don’t use the animation module, this will not be included in your bundle.
Performant
The output is heavily tweaked for performance
Being a compiler is a major differentiator from other JS frameworks like React, Vue or Angular.
One word, reactive
Reactivity plays a major part in modern ui applications. Data fetches and user events often need to translate in UI updates.
Svelte provides a easy way to develop reactive application by providing an elegant API for handling reactivity. It boils down to the following:
Use
$:
prefix to declare a reactive variable
Here’s an example:
<script>
let count = 0;
$: countPlusTwo = count + 2;
function increment() {
count++;
}
</script>
<button on:click={increment}>
{count} + 2 = {countPlusTwo}
</button>
By prepending $:
before countPlusTwo
we tell the framework this variable needs to be reactive. Every time count
changes it knows to recompute countPlusTwo
, updating the template.
If you’ve worked with RxJS this syntax feels very familiar. In RxJS we use the convention of appending $
to observable streams, which are also reactive values. In Svelte the $:
is prepended instead.
Although reactive variables are very easy to create, they are very powerful. Reactive values can be composed or chained together; creating streams that react to any changes in your application state.
Share state simply
State management in a Svelte application can happen on two levels: local and shared.
Local state management is done in the component itself. For example declaring a variable in the .svelte
component. Re-assigning a new value triggers a UI update.
Shared state management is done using the svelte/store
module. This module allows for the creation of stores which can be imported by one or multiple components in order to share state.
svelte/store
provides three methods:
writable()
readable()
derived()
This is a good example for well named functions. writable()
creates a writable store which components can read and write to. readable()
makes for read-only store and derived()
can be used for stores that are derived from existing writable or readable stores.
Here’s a short example for writable
:
// CounterStore.js
import {writable} from 'svelte/store';
export const count = writable(0);
// CounterButton.svelte
<script>
import { count } from './CounterStore';
function increment() {
count.update(n => n + 1);
}
</script>
<button on:click={{increment}}>
Increment
</button>
// CounterDisplay.svelte
<script>
import { count } from './CounterStore';
</script>
The current count is {$count}
Here we’ve created a writable store for the counter in order to share the state between the CounterButton
and the CounterDisplay
. If you look closely you see the imported count
variable is referenced as $count
. This is actually a shorthand for the subscription:
<script>
import { count } from './CounterStore';
let _count;
count.subscribe(c => {
_count = c
});
</script>
The current count is {count}
For a more extensive explanation check out the official tutorial.
No VDOM, yes performance
The major difference with other JS frameworks is that Svelte does not have a virtual DOM.
VDOM is a technique, introduced by React, of having a representation of the DOM in memory. Whenever the state changes a diff is done in memory and changes to the real DOM are patched.
The big three front-end frameworks all make use of a VDOM and do the diffing in memory during runtime.
Svelte is different. It does not have a VDOM and avoids this work entirely. Being a compiler and having the developer declare the reactive variables, it can figure out during run time exactly which elements can change. These elements are marked in the outputted code and invalidated when properties change, resulting in a very efficient UI update.
There is no need for VDOM.
By avoiding this work Svelte has best-in-class performance, all the while keeping a declaritive API.
Rich Harris, the creator of Svelte, wrote an excellent article on this: https://svelte.dev/blog/virtual-dom-is-pure-overhead.
Use for joy
I hope I’ve convinced you that using Svelte is simple, easy and fun. Use it and you’ll feel joy. The API is very concise and easy to learn. There is a lot of momentum; the community is growing and new tools and projects are published regularly.
However there is also a double meaning in this verse. Svelte is young, it is not as mature as the big three and in some cases, such as the build tooling, it can feel a bit rough around the edges.
So my advice for now is to try it out, experiment with it. It can give a new and fresh perspective on UI development. Personally I’m especially charmed by the reactivity system and the shared state management. The eco system is still young, there’s a lot of work ahead and you can be a major contributor in its success.
Nevertheless, for big projects I would still wait with using Svelte until the community has matured a bit and the tooling around framework has stabilized. Best practises are still being explored so it might benefit to wait a bit longer to see how it develops.
All in all, I’m impressed with the work that the Svelte creators and contributors have done. Keep up the good work! I am eager to see where this project is going.
Go forth and experiment!