We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to publish this job!

Login or register
to save this job!

Login or register
to save interesting jobs!

Login or register
to get access to all your job applications!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel 🚀.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Login or register
to save articles!

Login to see the application

Engineers who find a new job through WorksHub average a 15% increase in salary 🚀

You will be redirected back to this page right after signin

Blog hero image

Svelte: my new obsession

Pablo Alejandro Berganza Campos 4 August, 2021 | 6 min read

I admit I am the kind of person who gets immediately obsessed with something if it is new and interesting. That's how I got into Clojure, how I got into Rust, and how I got into the topic I'm writing about today: Svelte.

Svelte is not a new language I am learning, as it was with Rust and Clojure. It's a JavaScript framework for building single page applications (SPA). Like React, Vue or Angular. Its syntax may remind some people of Vue; but it has a major difference with the typical framework. Svelte does not have a runtime and, unlike the rest, it's not bundled with the rest of your code. Svelte is a compiler. It compiles your components into reactive JavaScript code that modifies the DOM directly. It will produce a small and more performant bundle.

How does it look?

Svelte tries to stay as close as possible to semantically correct HTML. This means that a simple HTML editor would do the trick for editing a Svelte component.

For example, the most minimalist component may look like this:

<p>Hello world!</p>

That's it! That's a valid Svelte component that the compiler will understand.

How to make it reactive?

Of course if you were going to write components like that, you would be better off writing plain HTML. The reason you're using a JavaScript framework is because you need a way to handle reactivity in your web application. So we need a way to add JavaScript to our component. As you would do with plain HTML, JavaScript can be added inside a script tag like this:

<script>
  console.log('Hello world!')
</script>

In order to add “state” to our component we just need to declare JavaScript variables:

<script>
  let message = 'Hello world!'
</script>

These variables can be accessed in the template by using curly braces. This is similar to how Vue does it.

<script>
  let messsage = 'Hello world!'
</script>

<p>{message}</p>

The message variable is reactive. If it were to change for some reason (e.g. an event), the contents of the p tag would be immediately updated. For example, we can create an input that updates the content of message.

The template of a Svelte component does not need to be a single element, so we can just add an input element right after the p element.

<script>
  let message = 'Hello world!'

  function onInput(event) {
    message = event.target.value
  }
</script>

<p>{message}</p>

<input value={message} on:input={onInput}>

But this is still too complicated. Svelte provides some “magic” directives in order to make certain operations easier. The bind directive helps with two-way data binding.

<script>
  let message = 'Hello world!'
</script>

<p>{message}</p>

<input bind:value={message}>

Svelte only handles reactivity on assignments. This means that array methods like push and pop won't trigger updates on the components.

Svelte also provides Handlebars like blocks to handle conditional rendering, asynchronicity and loops inside the templates.

What about styling?

Svelte provides a way to provide scoped styles to your components. As expected, this is done via the style HTML tag. Svelte will assign unique classes to each of your component's elements during compilation. You can use any valid CSS inside the tag, but a rollup/webpack plugin may be used to accept your favorite variant (e.g. SASS).

<h1>Hello world!</h1>

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

On compile time, the h1 tag will be assigned a class generated by Svelte and a CSS selector for this class will be added to the h1 on the style tag.

If you need to make the selector global you can wrap it in :global(...). For the example above, if we replaced h1 for :global(h1) it would apply the style globally to all h1 elements of the project. This can be really useful if your project contains dynamically generated HTML not controlled by Svelte, since Svelte wouldn't be able to assign unique classes to the elements inside it. Something like div :global(h1) would select all h1 elements inside all div elements of the component. This can be used to guarantee that the style remains scoped to the component.

Of course, you can always have a global CSS file to handle common styling for all components.

Join our newsletter
Join over 111,000 others and get access to exclusive content, job opportunities and more!

A more complete example

Here's how a simple to-do app would look like in Svelte:

<script>
  let todos = [], value = '';
  let filter = 'all';
  // The $: tells Svelte to make the statement reactive.
  // In this case, the assignment statement to "filtered" will be run
  // everytime "todos" changes.
  $: filtered = todos.filter(todo => {
    if (filter === 'checked') return todo.checked
    if (filter === 'unchecked') return !todo.checked
    return todo
  })
  function addTodo() {
    todos = [...todos, { value, id: Date.now(), checked: false }];
    value = '';
  }
  function toggleTodo(event) {
    const i = todos.findIndex(todo => todo.id === +event.target.id)
    todos[i].checked = event.target.checked
  }
</script>

<form>
  <label for=all>
    <input type=radio id=all value=all bind:group={filter}>
    All
  </label>
  <label for=checked>
    <input type=radio id=checked value=checked bind:group={filter}>
    Checked
  </label>
  <label for=unchecked>
    <input type=radio id=unchecked value=unchecked bind:group={filter}>
    Unchecked
  </label>
</form>
<form on:submit|preventDefault={addTodo}>
  <input bind:value>
  <button type=submit>Add Todo</button>
</form>
<ul>
  {#each filtered as todo, i (todo.id)}
    <li>
      <input
        id={todo.id}
        checked={todo.checked}
        type="checkbox"
        on:change={toggleTodo}
        >
      {todo.value}
    </li>
  {/each}
</ul>

<style>
  label {
      display: inline-block;
      margin: 0 10px;
  }
  li {
      list-style: none;
  }
</style>

This example uses some features I didn't talk about, but the official tutorial is great if you're interested in learning more.

Other features

Svelte also provides some other nice features, such as:

  • Built-in transitions and animations.
  • Easily access the document's head, window and body.
  • Lifecycles for the components.
  • Global stores.
  • Compatibility with server side rendering.
  • Components can be exported as web components.

Why rewrite the whole site?

Previously my site was written using Perun. It is a nice static site generator for Clojure that has tons of flexibility, since each step of the generation can be intercepted. But there were certain aspects of the generation that were hard to change or had little documentation. (I am not bashing on Perun, it is a perfectly great tool. I just wanted more freedom).

Perun generates a plain HTML output with no JavaScript. JavaScript needs to be injected manually. Each page is rendered by renderer functions written in Clojure which output HTML. Unless you installed extra packages, there is no built-in support for scoped styling. And, since the generator runs on top of the JVM, the generation of the site was quite slow.

This site is not written with plain Svelte. It is using Sapper. Sapper is a framework for Svelte inspired in Next.JS that allows to build server side rendered web applications. It can also export a static site like Next.JS does. This gives you much more freedom on how the site is generated at the cost of a bit more coding. For example, just as I did with Perun, each post's content source is a markdown file. But for Sapper I manually had to write the process the reads the markdown files and generates the HTML. This allowed me to use libraries I am much more familiar with, such as Marked for markdown parsing and Highlight.js for code highlighting.

The resulting site works as an SPA and has some features that I couldn't do previously, some of them:

  • Highlighting for GraphQL code.
  • Add working examples of code (such as the ones above).
  • Navigate the whole site without having to do a page reload.
  • Lazy loading of images.
  • Embedding external elements to blog posts, like YouTube videos.

It also brought some DX improvements such as:

  • Reusable components.
  • Scoped CSS styling, which helped with some headaches I had previously due to my lack of CSS knowledge.
  • Much faster generation of the static files.
  • Easily add more interactive elements to the site. (I might add a search bar for my blog posts at a later time).
  • It's easier to follow a more maintainable code structure.

One downside to using Svelte is its lack of TypeScript support (although this is being worked on). Another downside is that Sapper is still in early development, so I would not recommend it for serious projects. Svelte itself is ready for production, though. It also has a much smaller ecosystem than other mainstream frameworks.

Conclusion

Even taking into account the downsides mentioned before, Svelte/Sapper has been a joy to work with. In under 20 hours of combined work I managed to rewrite my whole site. Svelte should be an excellent choice for performance critical web applications, and it's syntax is easier to grasp compared to other frameworks. It should definitely not be considered a “toy” framework and I encourage you to add it to your tool set.

Originally published on pablo.berganza.dev

Related Issues

open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 2
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 2
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 1
  • Intermediate
  • HTML

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through WorksHub average a 15% increase in salary.

Start with GitHubStart with Stack OverflowStart with Email