Does Your JS Spark Joy? Svelte and the Future of the Web

tom0901

Tom Jackson

Posted on June 2, 2022

Does Your JS Spark Joy? Svelte and the Future of the Web

At You Gotta Love Frontend 2019 Rich Harris posed a simple question to the audience:

Does your JS spark joy?

Marie Kondo

The idea here was to demonstrate that writing less code is the only true way to improve performance by a meaningful margin.

I think we can take the question a step further though. In fact, applying the laser focussed minimalism of Marie Kondo to your code base is a neat way of summarising the core benefits of Svelte and gives you a good idea of how it's changing the web.

So, I'm going to begin and summarise this article by posing two questions to you.

However, before we begin, I think it's important to give a brief overview of the framework and its crucial differences from other component-based frameworks like React.

So what is Svelte?

Svelte is a compiler that does the job of a component-based framework. It takes your .svelte files and converts them into HTML, CSS and JS. Effectively moving the complexity of the framework to the build step so the runtime is smooth.

By comparison, traditional frameworks like React famously have expensive runtimes.

With Svelte your browser gets what it was built to run immediately; HTML, CSS and JS.

svelte

At this point, you might be asking how we achieve reactive state-driven apps this way. This is a valid question, but Svelte has a good answer. Unlike React with Svelte, you're not reliant on the Virtual DOM and expensive DOM diffing to manage and update your application's state. With Svelte the DOM tree is manipulated directly when state changes and, through some clever quirks of the compiler, this is achieved very efficiently by a single bundled JS file.

So, the TLDR is: Svelte leverages the familiar concept of moving our framework's runtime away from the client by compiling your declarative component-based code to imperative instructions the browser understands at build time.

All right, let's move on to those questions! Ultimately, as front-end developers, I think we should ask ourselves two questions.

Does our JS spark joy in us as developers?

Does our JS spark joy in our users?

If the answer to either of those questions is no, like Marie Kondo, we should thank it, then discard it.

Section 1

Does your JS spark joy in you as a developer?

Does it allow you to write simple maintainable declarative code?

Traditional component-based frameworks were created so you, the developer, could write neat understandable declarative code and avoid the hefty imperative implementation that's required to get the browser to actually do what you want.

With React, the trade-off for having this nice dev experience is an expensive runtime on the client.

However, with Svelte, because it's a compiler, the bundle size of Svelte itself isn't important - it's the output of that compiler that is actually being run. This has freed up the Svelte team to develop a remarkable developer experience.

Here are some of my favorite code examples that highlight Svelte's great developer experience.

Svelte's skinny syntax

React was a huge step forward, abstracting the imperative JS that actually manipulates the DOM into a much simpler format, but React also introduces a lot of boilerplate to hide that complexity behind its hooks.

Here's how you'd implement a simple form in React:

import React, { useState } from 'react';

export default () => {
    const [a, setA] = useState(1);
    const [b, setB] = useState(2);

    function handleChangeA(event) {
        setA(+event.target.value);
    }

    function handleChangeB(event) {
        setB(+event.target.value);
    }

    return (
        <div>
            <input type="number" value={a} onChange={handleChangeA}/>
            <input type="number" value={b} onChange={handleChangeB}/>

            <p>{a} + {b} = {a + b}</p>
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

Here's the equivalent code in Svelte:

<script>
    let a = 1;
    let b = 2;
</script>

<input type="number" bind:value={a}>
<input type="number" bind:value={b}>

<p>{a} + {b} = {a + b}</p>
Enter fullscreen mode Exit fullscreen mode

Svelte removes so much of that boilerplate leaving us with more readable maintainable code that is much more accessible to non-technical colleagues.

Svelte provides a better CSS experience

The basis of modern front-end frameworks is JS. When you write in React you are primarily working with JS but your browser serves HTML. This results in a subpar CSS experience for the React dev.

We all want CSS files that are scoped to our components and many of us want the HTML, CSS and JS that drive our component to live in one file. There are many solutions for achieving this with React but the downside of all of them is that they rely on installing extra dependencies and learning extra syntax to get this behavior.

With Svelte, because .svelte files are a superset of HTML we can simply include all of our HTML, CSS and JS in one file and the Svelte compiler will add unique hashes to our CSS classes to ensure they are scoped to their components. Here's what that looks like:

<script>
    alert('Hello world!')
</script>

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

<h1>Hello world!</h1>
Enter fullscreen mode Exit fullscreen mode

If you want to add global CSS, don't worry Svelte has you covered with the :global(...) modifier:

<style>
    :global(body) {
        /* this will apply to <body> */
        margin: 0;
    }

    div :global(strong) {
        /* this will apply to all <strong> elements, in any
             component, that are inside <div> elements belonging
             to this component */
        color: goldenrod;
    }

    p:global(.red) {
        /* this will apply to all <p> elements belonging to this 
             component with a class of red, even if class="red" does
             not initially appear in the markup, and is instead 
             added at runtime. This is useful when the class 
             of the element is dynamically applied, for instance 
             when updating the element's classList property directly. */
    }
</style>
Enter fullscreen mode Exit fullscreen mode

Svelte is truly reactive

For your program to be reactive, the dynamic variables within it have to be defined when you declare them.

The front-end community has been striving for an efficient way to write reactive code for a long time now and the solution we've settled on is the virtual DOM.

The virtual DOM is essentially a lightweight snapshot of your app's DOM structure. In React, every time your state changes that snapshot is compared to the previous one, and the real DOM is only changed where they differ.

This is a huge progression from previous frameworks that would rewrite large portions of the DOM tree just to make small changes. There is a 'but' here though. If we know ahead of runtime which variables depend on one another, we can change only what is necessary when our state changes without any comparisons. This is what Svelte does, the virtual DOM isn't fast it's merely faster than rewriting the whole tree. Direct DOM manipulation, if it is precise, has always been faster than the virtual DOM approach.

Svelte allows us to be explicit about which variables are dependent on one another. It allows us to create an app that knows which variables to update, the order to update them and is faster at updating them than it's competitors.

In order to understand how Svelte gets this behavior let's look at some examples lifted from Paul Stovel via Rich Harris.

var a = 10;
var b = a + 1;
a = 11;
b = a + 1;
Enter fullscreen mode Exit fullscreen mode

Here we can see that getting b to depend on a is clunky to say the least. It requires that any time we change a we also have to reassign b. As a solution to this problem, Paul Stovel proposed the theoretical destiny operator:


var a = 10;
var b <= a + 1;
a = 20;
Enter fullscreen mode Exit fullscreen mode

In this example, the <= binds the value of b to a. Unfortunately, this syntax doesn't exist in JS but, Svelte, being a compiler, is less constrained by the limitations of JS than other frameworks.

Svelte has leveraged this, to convert the labeled statement, a fairly unused piece of syntax, into the theoretical destiny operator.

let a = 10;
$: b = a * 2; 
Enter fullscreen mode Exit fullscreen mode

It's that simple - b is now bound to the value of a. Whenever a changes b will update. All the boilerplate React demands you write to get the equivalent behavior is gone. Yes, obviously there is still a lot of complexity hidden by the compiler but it's not forcing that boilerplate on you. What the client runs is efficient vanilla JS that directly manipulates only those parts of the DOM you have explicitly declared will change when your state does.

Essentially, because Svelte is a compiler, it has been able to drastically improve upon the front-end dev experience and this isn't just my opinion - Svelte was voted most loved Framework in the Stack Overflow 2021 developer survey.

Section 2

Does your JS spark joy in your users?

Does it help you deliver performant apps with great UX without compromising your developer experience?

The obvious benefit of Svelte being a compiler is that the bundle size the browser is served is significantly smaller. Svelte, according to this article, is 10 times smaller than React and ReactDOM when zipped. Not only is Svelte a lot easier for the browser to run, but once it's up and running it's faster too because it doesn't rely on virtual DOM diffing. That all translates to faster load times for your user and an app that is interactive more quickly.

Google page experience update

Last year's Google page experience update taught us that performance is the new SEO. It signaled the beginning of a new trend where UX is the most important factor in your app's search ranking. This major overhaul coupled with the increased traffic from low-performance devices has created an environment where Svelte really shines. Svelte, unlike React and Vue, can still offer great performance on low-performance devices like smart watches, payment terminals and smart TVs.

As developers, we have become obsessed with shipping one solution that works across all devices. We've ditched closely coupled legacy CMSs for shiny, headless offerings that can drive our content on all devices.

Why not take the same attitude with our front-end framework? React and Vue simply aren't options that will result in a responsive UX on a payment terminal. In this environment, Svelte is the only framework that is efficient enough, ultimately allowing you as a developer to work on a single tech stack that serves the range of devices that access the internet in 2022.

This brings us full circle, back to the original point Rich Harris was making at You Gotta Love Front End 2019. The only true way to increase the performance of our apps is to reduce their size. The only true way to give our users an excellent experience is to reduce the amount of JavaScript we are serving their device. Our two goals of having happy users and happy developers are both served by reducing the amount of code we write and ship.

Thank it, then discard it

Svelte means slender or elegant and the name is apt. The core benefits of Svelte all stem from the fact that it is a compiler and that that compilers output is, well, svelte. This allows us to do away with expensive run times in the browser, removes the constraints of needing our code to be read by the browser and it achieves all this without compromising on the developer experience.

The mantra of the first major JS framework JQuery was:

Write less, do more

Svelte, like JQuery in the Noughties is empowering developers to write more efficient minimal code that is accessible to more devices, users and developers. So, if your JS doesn't spark joy - thank it, then discard it.

💖 💪 🙅 🚩
tom0901
Tom Jackson

Posted on June 2, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related