easwee.net // tiny digital playground

devlog - svelte app development experience

This is a short write-up after completing a single page app project in Svelte.

The goal was to create an invoicing app that allows me to generate invoices for my company and export them into PDF with minimal click steps. It also includes conversion rates API fetching to support on-the-fly $ to € conversion, and simple client-side data storage inside IndexedDB, to prevent having to write in company data each time – ideal for recurring monthly invoices (I did not want to deal with setting up a server and database and user authentication at this point).

The initial setup really requires no effort. I decided to pick Rollup instead of Webpack as a bundler, just to test it out – no problems (your decision – both can be used).

So what is so amazing about Svelte?

First thing, writing your components requires minimal boilerplate. A custom date-picker component with change handler that fires and stores date into IndexedDB, and also fetches new conversion rates from API endpoint when user stops typing or picks a date, would look something like this:

<script>
  import { onMount } from "svelte";
  import { fetchRates } from "api";
  import { format } from "date-fns";
  import { rates, ownerData } from "store";
  import { idbRead, idbUpdate } from "utils";
  let typingTimeout = null;
  function handleInputChange() {
    window.clearTimeout(typingTimeout);
    $ownerData = $ownerData;
    typingTimeout = window.setTimeout(function() {
      idbUpdate("db", "owner", 1, $ownerData)
        .then(() => idbRead("biro_db", "owner", 1))
        .then(async result => {
          ownerData.set(result);
          const response = await fetchRates(
            format($ownerData.issue_date, "YYYY-MM-DD"),
            $ownerData.base_currency
          );
          rates.set(response.data.rates);
        });
    }, 500);
  }
</script>
<style>
  label {
    display: block;
    font-weight: 700;
    color: white;
    margin-bottom: 5px;
  }
</style>
<form>
  <div class="field">
    <label>Issue date:</label>
    <input
      type="date"
      bind:value={$ownerData.issue_date}
      on:keyup={() => handleInputChange()}
      on:change={() => handleInputChange()}
      placeholder="Issue date" />
  </div>
</form>

As you can see while there is quite some functionality done, the code itself is mostly plain html/js/css.

Proprietary syntax is:
– $ sign, which means automatic store subscription onMount and unsubscription on onDestroy (shorthand for store .subscribe()/.unsubscribe()methods). This makes it easy to read data from store inside templates.
– bind:value which makes two way data binding with input fields a piece of cake.
– on: event supports any of the regular js events.

The next thing that amazed me is how simple it is to create transitions with Svelte. For fading in and out a component when it mounts and unmounts all it takes is:

<script>
  import { fade } from "svelte/transition";
</script>
<div transition:fade>It fades!</div>

That’s it – and you have a fading element out of the box – and it’s a smooth CSS transition! Transition also accepts a configuration, so you can customize it to your likes.

The last thing I’d like to point out in this post (to avoid listing all the Svelte features, which are also nicely available in their online interactive tutorial) is the global store integration.
If you’ve been coding SPAs for last few years you may have dealt with at least 3-4 different libs for handling global state changes and you may know that most of them take some complexity in the process of making them work. Svelte comes with it’s own solution – with readable and writable stores and a bunch of other handy features and so far this has been the easiest one to implement for me. Some examples:

// define it in a store.js or wherever you want
export const rates = writable({USD: 0.8643});
// import it when you need it
import { rates } from "store";
// simply use it in code with $ shortcut
<p>Total is: {100 * $rates.USD}
// set it to a new value (let's say after API response)
rates.set(response.data.rates);
// .update() that takes function also available

Again no bloated code – clean and readable.

To recap: minimal boilerplate code, simple way of achieving transitions and animations and dirt simple global state management add so much to development speed that you can finally focus on developing features and stop wasting time on bloated patterns wrapped in tons of boilerplate code (khm… I’m looking at you Redux…) that at the end of the day don’t add anything to the final product and usability. All of this combined with performance that beats React’s speed in re-rendering definitely make me wanna use it again.

For more of Svelte’s features check out the interactive tutorial:
https://svelte.dev/tutorial/basics

Now there is one more question – would I use it in production?

If I was making a fully client based single page app with heavy animations and a lot of UX state changes – I would definitely dare to pitch it to a client. Svelte also offers Sapper, which we could say is an equivalent of Next.js, but at the time of writing this (august 2019) I haven’t dived into Sapper much yet, so I’m not confident enough to give an opinion on it, but we could say it is pretty much an equivalent to Next.js in terms of features. I would first like to understand how Svelte works fully and try out all of it’s features. Considering occasionally you still stumble upon some bugs, I want to be confident that I understand the mechanics of the basic Svelte library before diving into Sapper, so I can easily work around those (or maybe contribute a fix). An excellent point of reference for me is the very welcoming Svelte Discord community – live and active.

In conclusion I would say that Svelte is a framework I will be watching and using in the near future and I have a feeling it has great potential to grow in user adoption. Keep an eye on it!

Big thumbs up to the Svelte dev team!

P.S.: Maybe I should generalize the invoicer app and just release it to public – a TODO if I find some more time to spend on it.