CodeShare
I have a project called CodeShare, to create free and high-quality content in Portuguese, to reach more people in Brazil that didn’t have the opportunity to learn English yet.
So when I write a post there, I’ll post here as well, but in English (of course), so if you want to check the original version of this article (in Portuguese) you can check it here!
Introduction
You may have entered this article because you heard this name somewhere and don't know what it is, or you already know, but you want to know more about it or you can be just asking yourself something like "Why do I need another reactive UI lib if I already have React and Vue?". So, whatever reason that brought you here, prepare yourself because we're going on an adventure: A Walk on the Svelte Side is the new series of articles from CodeShare where I'll show what Svelte is, its main features and we will build examples along with this series and in the end you'll be ready to start using this lib in your projects!
This first article will be more theoretical, but that's really important to know how Svelte differs from other libs. I suggest that you read with attention so we can dive in the code after.
What is Svelte
Svelte, like other UI libs, is based in components, but with an essential and very important difference: it doesn't use the Virtual DOM differentiation like React or Vue.js because this libs use declarative structures that are converted into DOM operations that can overload a little the frames of our apps and also the Garbage Collector (in Portuguese).
But how Svelte works then? All the work is done in the build time, that way it converts all of your components to a high-performance imperative code that applies the fewest possible DOM operations, making that Svelte "disappears" completely of your final code. You'll have a pure, high-performance imperative JavaScript code. We can highlight some important aspects of Svelte:
- Extraordinary performance
- Small bundles
- Accessibility aspects included in the lib
- Styles encapsulation/isolation by default
- Declarative transitions included in the lib
- Learning curve
And in the end, the answer to our question: "What is Svelte?" can be answered saying that it's a compiler because its job is to compile the components into an imperative JavaScript code.
Reactivity on Svelte
Svelte version 3 was released on April 21 and brought huge changes to the lib, making that the written code is cleaner and improving how it works with the reactivity of the components. For example, before this version, to update the state of our components we needed something like:
const { clicks } = this.get()
this.set({ clicks: clicks + 1 })
If you already worked with React, you'll note a huge resemblance on how we handle the state on a class based component (before the launch of the famous Hooks):
const { clicks } = this.state
this.setState({ clicks: clicks + 1 })
With the launch of the Hooks, the way that React works with the state of the components has changed significantly and some other libs started to create their own version of the Hooks. Svelte didn't want to follow this path, because behind the curtains they create some overload to the Garbage Collector (in Portuguese) and if you need to run this code on an embedded device or if your app relies on many animation-based interactions this can lead to some issues.
So how Svelte 3 works with reactivity and updating a component state? In a very simple way, without using proxies or nothing like that. When we want to change for example a state variable named clicks
, we just need to update it:
clicks += 1
Since Svelte's job is done in the app build time, for being a compiler, it can only do the instrumentation of these updates without any additional complexity. Behind the curtains what he does is:
clicks += 1
$$invalidate('count', count)
Performance on Svelte
One of the main diff between Svelte and other libs like React and Vue is that it doesn't use the Virtual DOM, but you must be thinking: how can it be so fast without using the Virtual DOM? If you work with Front-end (or even with Back-end, but like to read about), probably you already heard about the Virtual DOM and that working with it is more performant than with the Real DOM.
But what's the Virtual DOM and how the libs work with it? In a very simple way, the Virtual DOM is only a JavaScript object that defines the basic structure of your page. When a change occurs in the state of your application, for example, the value of some property is updated, it's created a new object and the lib work is to find the diff between the old and the new object and apply the fewest number of updates in the Real DOM.
In practice, there is no way to make any changes to the Real DOM without first comparing the two states of the Virtual DOM, but this can lead to some unnecessary steps. Svelte works as a compiler, in the app build time it already knows how the state of the application can be changed, so it generates the fewest possible steps to manage this possible changes without having any work during application execution.
Creating our first Svelte component
One of the main features of Svelte is to let us build apps in a simple way and writing less code. The longest the code, greater will be the effort to understand it and the chance of having bugs increases, so when we write less code, we have the benefit of being able to understand it faster and introducing fewer bugs.
Let's create our first component, it will be something really simple. We will have two text fields where we can provide our first and last name respectively and it will be shown a welcome message on the screen with our full name. Svelte components use the .svelte
extension where we declare:
the behaviour of our component with JavaScript inside a
<script>
tagthe style of our component with CSS inside a
<style>
tag, the styles that we declare on a component have a restrict scope to that component, that means that if you create a rule to change the style of the<p>
tags of your component, it won't affect any other<p>
tag outside your componentthe structure of our component with HTML, it is not necessary to encapsulate this structure in a
<template>
tag as we do on Vue, and also may have several root elements, other than the React that we can return only one element or use the Fragments.
First, we have the behaviour part of our component that will be a totally normal and basic JavaScript code. We will create two variables and define a function that we will use when we define the structure of our component:
<script>
let firstName = ''
let lastName = ''
function showGreeting () {
window.alert(`Welcome, ${firstName} ${lastName}`)
}
</script>
Below we will also define the style of our component that is also a normal CSS code, the only difference is that the styles declared here will affect only the elements of this component:
<style>
* {
font-family: sans-serif;
}
p {
font-weight: 700;
}
.warning {
color: #ff2b56;
}
</style>
The last part of our component is the structure of our component, that's done with HTML, with only some little details that we will check after:
<label for="first_name">First name:</label>
<input id="first_name" type="text" bind:value={firstName}>
<label for="last_name">Last name:</label>
<input id="last_name" type="text" bind:value={lastName}>
{#if firstName.length > 0 && lastName.length > 0}
<p>Hello, {`${firstName} ${lastName}`}</p>
<p>
<button type="button" on:click={showGreeting}>Show alert greeting!</button>
</p>
{:else}
<p class="warning">Type your first and last name above...</p>
{/if}
As you can see we have some details that aren't an HTML code in our structure, but that is used to connect the structure of our component with its behaviour. In our <input>
elements the attribute value
is changed to bind:value={variable}
, where we link a state variable of our component so that when this variable is changed the change will be reflected in the <input>
element and vice versa.
Just as it is easy to link state variables, invoking functions that we define when an event occurs in the DOM is also very easy, we use on:event={function}
. In our code, when the button receives a click it will invoke our showGreeting
function defined above.
Often we need to show or hide some content according to the state of our component, Svelte gives us a simple way to do this with the blocks: {#if} {:else if} {:else} {/if}
, this way we can control in a simple and clean way what and when to display and hide some content.
Our example can be seen in the CodeSandbox below:
As you can see in the CodeSandbox above, we have a index.js
file that imports our component and renders it in the <body>
. This file alongside with the files package.json
and the config for Rollup, the default bundler that Svelte uses, rollup.config.js
are already included in the default template for Svelte.
You can play on the CodeSandbox to not need to create the projects locally, but if you want to is really easy as well. We can use NPX to create our project in a simple way:
npx degit sveltejs/template my-app && cd my-app && yarn
That way you'll create a project using a tool called Degit that will create a copy of this repository that's the minimum default template for an app, with all the needed config. If you prefer or want to make any changes to this default template you can fork this repository and change the command above to use your Github user:
npx degit your-github-user/template my-app && cd my-app && yarn
In the README.md
file of this template you'll find instructions on how to run your project locally and also instructions on how to deploy your app.
Conclusion
In this first article we saw what Svelte is, its main features and we built our first component to see how it works. In the next articles we will go deeper on other features of this lib while we create examples to put in practice the concepts we will learn.
I hope that you liked this article and if you do, don't forget about commenting and sharing this article with your friends!!! See ya! 😎
Top comments (0)