Hands-on with Svelte

Svelte works on the server side to compile your app into optimized JavaScript. Let’s take a quick tour of this fast, reactive component framework.

Hands-on with Svelte
Thinkstock

As 2021 nears the halfway mark, the golden age of JavaScript continues. One of the most exciting characters in the current chapter is the Svelte framework. This article gives you the basics for creating a Svelte project and using some simple UI elements.

In a distinctive departure from the current groupthink represented by React, Angular, and Vue, Svelte works on the server side to compile your application into optimized JavaScript. That means that Svelte requires a build pipeline setup. 

Although setting up a build pipeline might seem like extra work, the truth is that all real development in React, Angular, or Vue requires a build pipeline in some form anyway (like create-react-app or Webpack configuration). Plus setting up the Svelte environment quickly gets you things like hot-deploy dev mode.

Svelte setup

Let’s jump right in and set up a simple build environment. You are going to use npx and degit for the purposes of creating a starter template. Use the steps in Listing 1.

Listing 1. Initial template

npx degit sveltejs/template infoworld-svelte
cd infoworld-svelte
npm install
npm run dev

At this point the starter app will be running at localhost:5000; check it out in your browser. Open the /infoworld-svelte folder in your code editor or IDE. There are two source files of interest in the /src directory: App.svelte and main.js. These two work together to define what you see in the browser.

Note: All of the code is avaiable in this repo.

If you use Visual Studio Code, there are a number of useful (free) Svelte extensions that provide syntax highlighting and autocomplete.

To find them, go to the extensions tool on the left and enter “ext:svelte” into the search bar.

main.js is the main entry point for the app. It imports App.svelte in the first line as seen in Listing 2.

Listing 2. main.js

import App from './App.svelte';
const app = new App({
            target: document.body,
            props: {
                        name: 'world',
            }
});

export default app;

Listing 2 shows something interesting about how Svelte works: The export from App.svelte has been transformed into an object, which is instantiated with the new App({...}) call.

The App object is configured with a couple of parameters. These are used to supply the values for the Svelte object’s params. The target param is a built-in property that Svelte uses to tell where the root of the app is (similar to the second argument of ReactDOM.render).

Now look at App.svelte. This has the meat of the component syntax in Svelte, which combines the three elements of JavaScript, markup, and CSS with script, main, and style tags, respectively. These are combined together, along with the parameters provided by the instantiation in main.js, into a component. Note that the main tag could be any valid HTML tag.

Notice that Svelte uses variable tokens in the same syntax as the other frameworks: <h1>Hello {name}!</h1>. Notice also that this variable, whose value is supplied by the params in main.js, is exported in the script section: export let name;. This could also be done directly in the script. To see what I mean, change this line to let name = "InfoWorld";, eliminating the export entirely. The point being, there is nothing magical or required about parameterizing the App object via main.js. It is just a supported feature for organizing things.

Since you are running in dev mode, the change will be reflected immediately. The browser will now show the new greeting, “Hello InfoWorld!”

The are many features necessary to building sophisticated UIs. Among the most essential are iterators and object handling. Let’s have a look by adding the code seen in Listing 3.

Listing 3. Iterating over an array of objects

<script>
            let quotes = [
                        {author:"Emerson", quote:"To be great is to be misunderstood."},
                        {author:"James", quote:"The art of being wise is the art of knowing what to overlook."},
                        {author:"Thoreau", quote:"That government is best which governs least."}
            ];
</script>
<main>
  <ul>
                        {#each quotes as { quote, author }, i}
                                    <li>{i} - {quote}</li>               
                        {/each}
  </ul>
</main>

The basic syntax is the {#each} tag. This is used to reference the variable quotes. The elements of this array variable are then exposed (via destructuring) to the internals of the tag, along with an iterator counter i. These exposed variables are then referenced with the same token syntax as any other variable. If you are familiar with another framework, I think you’ll agree the syntax is very concise here.

Event handling in Svelte

Adding handlers like onClick is similarly easy. You can add one to the list items as seen in Listing 4.

Listing 4. Adding an onClick handler

<script>
...
function click(){           alert("ok"); }
...
</script>
<main>
...
<li on:click="{click}">{i} - {quote}</li>           
...
</main>

The event handling syntax is fairly self-explanatory. You can also pass in params to the handler by wrapping the handler function, like so:

<li on:click="{() => click(author)}">{i} - {quote}</li>

This can be used by the handler function:

function click(author){ alert("hello from " + author); }

Svelte components and inputs

Now get a taste for the component system, along with two-way binding of input elements. You are adding a new component that will create quotes to add to the list. First, create a new file called /src/AddQuote.svelte and paste in the contents of Listing 5.

Listing 5. The AddQuote component (event dispatch and input binding)

<script>
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher(); // create dispatcher
  let author = "";
  let quote = "";
  function onAdd(author, quote){
    dispatch('quote', { // use dispatcher
                                    author: author, quote: quote
                        });
  }
</script>

<main>
  <div class="add-quote">
    <h2>New Quote</h2>
    <div>Author: <input bind:value={author} placeholder="Author"></div>
    <div>Quote: <input bind:value={quote} placeholder="Quote"></div>
    <button on:click={()=>{onAdd(author, quote)}}>Add It!</button>
  </div>
</main>

Component events

Several new concepts are introduced here. First is component events. These are events that components can raise and that are handled by other components just like DOM events. The basic process is to import the createEventDispatcher from Svelte, then use it to create a dispatcher function. This dispatcher function is called and passed the name of the event ('quote') and the content of the event (in this case, the new quote information).

This event is then handled by our App component, as we’ll see in a moment.

Input bindings

Binding the HTML inputs, aka two-way bindings, is also simple. You can see this in the main element of Listing 5. Notice the bind:value attributes on the input elements. These reference the variables to which the input will be bound—in this case, the author and quote variables.

You then use a button element with an onClick handler to raise the dispatch event in the onAdd function.

Catching custom events in Svelte

Back in the App.svelte file, you can use the AddQuote component as seen in Listing 6.

Listing 6. Using the AddQuote component

<script>
...
            function onAddQuote(event){
                        quotes = [...quotes, {author:event.detail.author, quote:event.detail.quote}];
            }
</script>
...
<main>
...
<AddQuote on:quote={onAddQuote}></AddQuote>
...
</main>

Listing 6 shows how, in the markup, you use on:quote to listen for the custom quote event and send it to the handler function, onAddQuote, which is defined in the script section. This function is handed the event, which contains the event object we sent in AddQuote in the event.detail member.

From there it’s a simple matter of updating the data in the quotes array to reflect the new item. Note though that you must update the array with an assignment, or Svelte won’t notice the change. In other words, just using Array.push won’t trigger the update. (This is similar to other reactive frameworks.)

API fetching in Svelte

As a quick extra bonus, let’s see how quickly we can add a remote API fetch to this app. Listing 7 shows how to add an API fetch to App.svelte.

Listing 7. Using a REST API (App.svelte)

<script>
...
            async function addRandom(){
                        const res = await fetch("https://api.quotable.io/random");
                        const json = await res.json();
                        quotes = [...quotes, {author:json.author, quote:json.content}];
            }
</script>
...
<main>
...
<button on:click={addRandom}>Add Random Quote</button>
...
</main>

Listing 7 adds a button that calls the async addRandom function. This function simply calls the remote quote API and then updates the quotes array with the new quote. Simple!

This has been a whirlwind tour of some key features of Svelte. There are many more capabilities in the framework, and it is up to the task of building enterprise interfaces right now.

Svelte is also making fast gains in the marketplace. It is fourth in usage after the big three (React, Angular, and Vue) but first in developer satisfaction and first in interest.

Copyright © 2021 IDG Communications, Inc.