loading...

SvelteJS: The next big UI framework

mstamstrom profile image Marcus Stamström ・8 min read

SvelteJS header picture

SvelteJS: The next big UI framework

SvelteJS is the new UI framework on the block. Svelte is however very different in many aspects and especially in its mindset around how a UI framework should work and how it should solve the problems regarding writing a user interface. In this post, we will explore how to get started with SvelteJS by building a todo app (as always 😃 ). We will at the same time learn about what Svelte brings to the table and how it works.

TL:DR

SvelteJS is a compiler UI framework, some of its features are:

  • Truly reactive framework
  • Easy to learn
  • Accessibility support
  • Super fast and small bundle sizes
  • Scoped CSS
  • Fullfledge framework with a big toolbox to help develop faster.

Stay around and we will explore all this and more in this article.

What is Svelte?

Svelte is a framework for building user interfaces, like Vue or React. The key difference is that Svelte is a compiler, unlike React or Vue which runs in the browser. This key difference together with that Svelte is truly a reactive framework (which I would argue that React and Vue are not) opens a lot of opportunities that we will explore in this post.

In Svelte, we write code in the same declarative way as we do in for example React or VueJS. We do really notice that the UI framework is a compiler, which we also will see in the examples later on.

How do we get started?

The easiest way to get started is to download a boilerplate template from npx or start a project in codesandbox. To create a boilerplate template:

npx degit sveltejs/template my-todo-app
cd my-todo-app/

npm install
npm run dev

Easy as cake. Now we have a SvelteJS setup ready and can start coding. This project is setup with rollup, which is a bundler, like webpack but more minimalistic.

The boilerplate template with SvelteJS

At first glance, the project structure looks quite similar to what you would get from React or Vue from scratch.

Svelte project structure

Notice that we have a main.js file, which basically does the same as for other UI frameworks, that is injecting the created js bundle into an HTML element. That's all about the setup, let us check out the code.

Svelte components

SvelteJS components are similar to HTML files, but with a lot of sugar on top. Javascript is typed in a script tag and CSS is typed in a style tag. The rest is interpreted as HTML. Here is the App.svelte component which comes with the template:

<script>
  export let name;
</script>

<style>
  h1 {
    color: purple;
  }
</style>

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

It prints the name variable which is passed in from main.js. So that’s the first thing we can see that is different syntactically. Props are those properties that are exported in the script tag.

Reactivity by assignment

But we want to create a todo app so let's start making changes. Let us start by adding an input field and connect that with a variable

First code example

Pretty similar to React or Vue, but with a lot less boilerplate. We have a todo variable which gets updated when the value in the input field is changed.

Notice that we are using the assignment operator. The assignment operator is a big part of SvelteJS reactivity system. When assigning a new value to a variable, that assignment will also tell SvelteJS that something has changed in the App and that Svelte needs to update the variable in the DOM in the end of the event loop. Yes, there is an event loop to batch DOM updates, which is good for minimizing repaints.

We can actually make this a little cleaner with the help of the SvelteJS two-way data binding directive.
Second code example

And it still works like before. We are using the bind directive to use both read and write operation for HTML elements. This also works for checkboxes and other kinds of inputs.

Let's continue coding and check how to iterate over arrays.
Third code example

Now we have added the possibility to add todos to an array and display those added todos. There are some important observations in the newly added code:

  • the ${each} command in the HTML iterates over an array, with the item as its first parameter and the index as its second parameter. Notice that we have to close the iteration with {/each}. To use the index write {#each todos as (todo, index)}

  • on line 5 we reassign the array instead of using push, in SvelteJS, using operations like push will not trigger an update of that value. This is a very important observation, as we mentioned previously SvelteJS reactivity system is built around the use of the assignment operator. So we cant use operations that don't return the updated variable. Push returns the length of the array after adding a new item.

  • In React, VueJs and other frameworks we need to have a wrapping element for each component. In SvelteJS we don't need a wrapping element for each component, which helps avoid div nesting issues.

  • There is no this in the component. Since SvelteJS is a compiler, it doesn't have to apply all the rules that UI frameworks that run in the browser have to.

But we are not completely reactive yet

Now we have seen some examples of how reactivity works in SvelteJS. It works a bit different since the code is compiled at compile time and only run once in the browser. We have seen how we can have variables in the HTML and if we assign a new value to that variable, the DOM also updates. But what if we have a variable that depends on another variable. Let's consider this example:

  let isDone = false;
  const infoMessage = isDone ? 'You finished' : 'Keep going!!'

If we would change the isDone variable somewhere in the code, that would not recompute infoMessage. As we just mentioned, that is because the code only run once. Let's take another example with our todo app, which now has the possibility to set todos as done as well as filtering on remaining todos.
Fourth code example

As we can see in this example, it's not reactive. I click the checkbox to hide buy groceries, but it's not disappearing. That's because our code only run once.

Svelte has come up with a solution for this problem, by "adding" a reactive command. We can add a $:, which is valid javascript and is a labeled statement. It doesn't really do anything so Svelte uses this for reactivity. How that work is that the $: is like a subscription and subscribes to the values in the expression. So if we revisit our example and do this change, then it should work.

Fifth code example

With this change, our todo app is now reactive and filters out the done todos when selecting the checkbox.

How that works more exactly is that this code runs in topological order. Which means that filteredTodos depend on onlyShowRemainingTodos and filtreredTodos will run after onlyShowRemainingTodos has changed. This means we can also have reactive values that depend on other reactive values. We could, for example, have a variable that depends on filtered todos:

let todos = [
  {id: 0, text: 'Buy groceries', isDone: false},
  {id: 1, text: 'Go to the Gym', isDone: false}];
let onlyShowRemainingTodos = false;

$: filteredTodos = onlyShowRemainingTodos ?
  todos.filter(x => !x.isDone) : todos;
$: numberOfFilteredTodos = filteredTodos.length;

Scoped CSS

All CSS in the style tag is by default scoped, which is really awesome. This means we don't have to worry about complicated naming schemes like BEM or using pre-processors. You could still use BEM or pre-processors if you want to, but there aren't as many benefits when the global CSS issues are already solved. What scoped CSS gives us, is that the CSS is specific for each component. So we can have the same CSS class in 2 different components without having name collision.
Example scoped CSS

As we can see in this example, svelte hashes our CSS to be specific for the App component, thereby making it scoped. Also notice that I added a CSS class that is not used in the HTML. That CSS class will not be included by Svelte in the CSS bundle, since it's not used anywhere.

Other key features

So far we have covered some of the features in SvelteJS, there are however a lot more. We will touch on some more features briefly, but we won't go through all of them in this article. For complete code example and to see all the features, I encourage you to visit svelte.dev

Performance

In the compile process, Svelte compiles our svelte components into high-performance imperative javascript code. This makes our code very fast to run for the browser. As I mentioned, our code only runs once and not every time some state changes, which is a huge performance benefit. When Svelte turns our declarative code into high-performance imperative code, it also disappears from our bundle, since all the logic for updating the DOM is done in the build process and what's left of SvelteJS in our bundle is just some helper functions.

Okay, so we have small bundles which mean faster loading time and faster time to first interactivity and our app is faster due to the imperative code. What not to like 😃

No virtual DOM

With Svelte, all the computation for working out the most efficient way of reacting to a state change is done beforehand. With this way of thinking, we don't need a virtual DOM. The virtual DOM can now actually be seen as a bottleneck for performance. Svelte does not use a virtual DOM and is much faster because of it.

Easy to learn

Unlike most other frameworks, Svelte components look like HTML with javascript and CSS put in script and style tags. This makes the code more familiar to those not experienced with any UI frameworks. For those who are already using UI frameworks, its very easy to get started as well.

There is also very little boilerplate, which makes it very easy to read and understand. This is a big selling point when learning a new framework, it lets you do what you are supposed to do, without typing much framework specific code.

Fullfledge framework

That SvelteJS is a compiler also gives us an advantage when it comes to which features that Svelte can include in the framework. It gives Svelte the advantage of including a lot of features, but its only the features that you use in the app that will be included in the bundle. The rest of the feature will be tree shaken away. That is really great, it gives us a very big toolbox to choose from, making development easier, without having to pay for the features we aren't using.

Conclusion

I think Svelte is a really great framework. It's easy to learn, fast and has a lot of usable and cool features. It gives a different mindset about how to think about UI frameworks in terms of reactivity and what a UI framework should help to solve. It feels easy to start working with Svelte because of their big toolbox and we don't have to worry as much about performance. I think Svelte will become one of the big UI frameworks in the future and I hope I have inspired you to give it a try, either by following my steps and setting up your own project or go svelte.dev and try some of the tutorial steps.

Thanks for reading !!

Discussion

pic
Editor guide
Collapse
jdmg94 profile image
José Muñoz

I don't necessarily agree with the "virtual dom is a bottleneck" argument, Attachment is an expensive process for the browser and the whole purpose of the virtual DOM is to prevent unnecessary re-paints. I am also curious of how well does Svelte works with immutability as it seems to rely on change-detection as opposed to unidirectional data-flow. Lastly, the word framework has been thrown around but neither Vue or React are frameworks but libraries, and I think Svelte fits that description as well as there are no set ways of doing the data-layer like Angular.

Collapse
mstamstrom profile image
Marcus Stamström Author

Thanks for reading and thank you for the comments.

I didn't expand on why I think the virtual DOM is a bottleneck. The short answer is that it performs a lot of unnecessary DOM diffing in the process of deciding what to update, since when using the virtual DOM the framework/library don't have any trace of the data flow. A lot of code also runs more times than necessary. If you don't trust, check out the talk by one of the founders of SvelteJS (youtu.be/AdNJ3fydeao).

I think you could use immutability, but I haven't tried it. But looks like you could do something like this(svelte.dev/tutorial/svelte-options)

Svelte has a store feature for handling data if that's what you are referring to.

Collapse
jdmg94 profile image
José Muñoz

Thanks for the reply, I'll watch the talk!

Collapse
tobiassn profile image
Tobias SN

Please explain why React and Vue are not “truly reactive”.

Collapse
mstamstrom profile image
Marcus Stamström Author

Thank you for the comment!

React and VueJs don’t make use of reactive programming. That is, they don’t track the data flow through the application.

Instead they treat the application as a black box and when a state changes, they rerender the whole component and all it’s children, instead of just the changed value.

Collapse
tobiassn profile image
Tobias SN

Technically that doesn’t make it less “truly reactive” than Svelte, since reactivity doesn’t care about how the app itself or the rendering system works.

Thread Thread
mstamstrom profile image
Marcus Stamström Author

To me reactive programming is to track data and the data flow through the application and when a state variable changes, update the variables that depend on that changed variable.

React and Vue cannot track which places to update when a state variable changes and as a result updates the whole component where the state variable resides as well as all its children. Thereby, in my opinion, does not apply reactive programming principles.

Svelte on the other hand, can track data through the application and only update the variables that depend on the variable that's updated. Which in my opinion better applies to reactive programming.

Hope my explanation makes sense. If you want a more thorough explanation, then I recommend you to watch Rich Harris talk on rethinking reactivity (youtu.be/AdNJ3fydeao).

Thread Thread
tobiassn profile image
Tobias SN

According to Wikipedia, “reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change.”. So basically if I say a = b + c, a will change when b or c change, and it doesn’t matter how it’s implemented.

Thread Thread
mstamstrom profile image
Marcus Stamström Author

Yes, that is true. But the article you are referring to also state that

"in reactive programming, the value of a is automatically updated whenever the values of b or c change, without the program having to re-execute the statement a:=b+c to determine the presently assigned value of a."

In react or VueJS, when a value like a in your example changes, we have to rerun the same code and thereby re-execute the statement a = b + c. Making React or VueJS not reactive by that definition. In SvelteJS, the values are automatically updated as in the definition.

Thread Thread
tobiassn profile image
Tobias SN

Not sure how Svelte would know what a is without rerunning that code.

Thread Thread
mstamstrom profile image
Marcus Stamström Author

In Svelte, we can reassign the value of a without redeclaring the inline function. Which we would have to do in React.

That is one of my points about Svelte being truly reactive.

Thread Thread
tobiassn profile image
Tobias SN

Not sure what you mean by “redeclaring the inline function”.

Collapse
shailennaidoo profile image
Shailen Naidoo

Thanks for the great article Marcus, I loved the read! I have looked into Svelte on many occasions but me being a lover of progressive enhancement Svelte does not really fit into this model (I might be mistaken) as you cannot just add Svelte to an existing static HTML page like Vue.js or even React.js and that's what does not make it as appealing but I do see that it has a place in really optimized applications with loads of dynamics but I can't really tell until I build something with it :)

I forgot to mention that I am a big Vue fan so I might be biased.

Collapse
mstamstrom profile image
Marcus Stamström Author

Thanks for reading!

But yes, you can use Svelte for progressive enhancement, juse like for Vue or React. You inject it just as you would with vue or React, you can even add svelte to a react or vue app if you would like.

I also like both Vue, React and Angular. However, I like the way Svelte is making us think about creating user interfaces.

Collapse
shailennaidoo profile image
Shailen Naidoo

I'll definitely give it a closer look, thanks :)

Collapse
stegriff profile image
Stephen Griffiths

Grateful that you wrote this as it means I don't have to look up elsewhere what Svelte is all about :) And your description was very easy to digest! I like that they have gone for the very vanilla JavaScript feeling, but I'm not a big fan of things like the $: label - seems like a bit of hack... 😅

Collapse
mstamstrom profile image
Marcus Stamström Author

Thank you for the nice comment 😊

The $: is valid JavaScript, however I get that it can feel a bit unusual at first. I think we can get used to it, since it gives so much value. You can for instance also use it for watching log messages,

$: console.log(value)

That will print every time value changes, which is very useful for debugging as well.

Collapse
oxyyyyy profile image
Alexandr Vlasenko

Thanks for the article, it has really inspired me to try Svelte :]
But what about large applications? Are there any references?

Collapse
mstamstrom profile image
Marcus Stamström Author

Thank you for reading and for the nice comment 😊

For building larger applications, there is a project called Sapper. Sapper helps with code splitting, E2E testing and a lot of other nice features.

Companies like New York Times and goDaddy use Svelte. The have a list of companies on their site.