Yesterday I tried Svelte to see what all the fuss is about. Version 3.0.0 came out recently and it smells like Svelte is ready for the big time.
You can watch the livestream here 👇
Created by @rich_harris, Svelte's unique idea is that there's no runtime. The framework compiles itself away to become vanilla JavaScript and create the smallest bundles you ever did see.
Plus a few features to make development absolutely painless:
- plain JavaScript in every file
- plain CSS automatically scoped to components
- plain HTML ... with some additions
- no state management
You can use plain HTML. You need the extensions to interact with Svelte and your code. Such is life.
Building with Svelte feels like magic. Lemme show you 👇
Building a Marvel movie timeline with Svelte
We built a Marvel Movie timeline; 22 movies sorted by their timeline inside the Marvel Cinematic Universe. The AMC website helped out with a list coz I had no idea there were so many Marvel movies 😅
Click 👆 to try it in action. Total JavaScript size just 17.2KB, or 7.2KB when compressed for transfer.
That still sounds like a lot for this app, but it's less than React where you some 40KB goes just to React itself. The CSS compiled into a 1KB file with random classes for scoping. There's nothing else.
App loads fast and works fast 👌
You can see the full code on GitHub. Importing the repo into CodeSandbox didn't quite work and I'm not sure why.
Best way to start a new Svelte project is with the CLI
$ npx degit sveltejs/template my-svelte-project $ cd my-svelte-project $ yarn install $ yarn dev
That creates a new Hello World
project in my-svelte-project
and runs the dev server. Go to localhost:5000
and start hacking. Every change triggers a page reload so you can see what you're doing.
I didn't have to install anything new to make the above commands work 🤷♂️
A Svelte component
Svelte components live in .svelte
files, split into 3 sections:
- JavaScript inside
<script>
tags - CSS inside
<style>
tags - HTML at the bottom
Our App.svelte
component looks like this.
// src/App.svelte
<script>
// import other components
import MarvelMovies from "./MarvelMovies.js";
import Movie from "./Movie.svelte";
import Header from "./Header.svelte";
import Footer from "./Footer.svelte";
// this is automatically reactive
let index = 0;
// assigning new values in functions triggers re-renders
function nextMovie() {
index = (index + 1) % MarvelMovies.length;
}
function prevMovie() {
index = index - 1;
if (index < 0) {
index = MarvelMovies.length - 1;
}
}
</script>
<style>
// all of this gets scoped to your component
.grid-container {
display: grid;
grid-template-columns: 0.1fr 2.9fr 0.1fr;
grid-template-rows: 0.1fr 2.8fr 0.1fr;
grid-template-areas: "h1 h2 h3" "b1 b2 b3" "f1 f2 f3";
}
button {
cursor: pointer;
}
</style>
// free floating HTML is kinda neat
<div class="grid-container">
<Header />
<button on:click={prevMovie} style="grid-area:b1">👈</button>
<Movie {...MarvelMovies[index]} />
<button on:click={nextMovie} style="grid-area:b3">👉</button>
<Footer />
</div>
You might wanna install the Svelte plugin for VSCode to have proper syntax highlighting, Prettier support, and all the rest. The plugin did cause some weird issues while I was streaming, but who knows what that was.
A few interesting things to note about App.svelte
:
- You can import
.svelte
components just like normal JavaScript - Every
let
variable becomes reactive by default - Assigning new values in functions triggers re-renders. No need to think about any of that
- Your CSS is scoped to your component so there's no bleed-over
- Your HTML free-floats at the bottom
- Just like in JSX, Svelte components become HTML-like elements
- Dynamic values go in curly braces,
{}
, same as JSX
My favorite way to use custom components and add dynamic values to HTML. Vue's approach never quite made sense to me 😇
A Svelte component with props
Where I think Svelte really shines is building components for re-use. Like the <Movie />
component we used above to render the Movie view.
// src/Movie.svelte
<script>
export let title;
export let description;
export let image;
export let yearOut;
</script>
<style>
.main {
grid-area: b2;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 0.1fr 400px 1.1fr;
grid-template-areas: "title" "thumbnail" "description";
}
h2 {
text-align: center;
grid-area: title;
}
img {
max-height: 100%;
max-width: 640px;
display: block;
}
.thumbnail {
grid-area: thumbnail;
display: flex;
justify-content: center;
align-items: center;
}
p {
grid-area: description;
padding: 0 1em;
}
</style>
<div class="main">
<h2>{title}</h2>
<div class="thumbnail">
<img src={image} alt={`${title} movie thumbnail`} />
</div>
<p>{description}</p>
</div>
Yep it's mostly CSS.
You declare props by exporting let
variables. Use them just like you would props in React 👉 <Movie title="Iron Man" description="..." />
.
Because our Movie props come from a variable, we used a spread and that worked too. <Movie {...MarvelMovies[index]} />
.
Notice that my CSS is very sloppy.
I'm redefining h2
, img
, and p
tags and yet it's totally fine. Svelte scopes it all to the <Movie>
component.
Whatever CSS you write here affects this file/component only and that's neat.
Plus there was no boilerplate at all to get props working, reactive, and passed into the template. To be fair, the same React component looks like this:
// <Movie> as React
const Style = styled.div`
grid-area: b2;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 0.1fr 400px 1.1fr;
grid-template-areas: "title" "thumbnail" "description";
h2 {
text-align: center;
grid-area: title;
}
img {
max-height: 100%;
max-width: 640px;
display: block;
}
.thumbnail {
grid-area: thumbnail;
display: flex;
justify-content: center;
align-items: center;
}
p {
grid-area: description;
padding: 0 1em;
}
`
const Movie = ({ title, description, image, yearOut }) => (
<Style>
<h2>{title}</h2>
<div class="thumbnail">
<img src={image} alt={`${title} movie thumbnail`} />
</div>
<p>{description}</p>
</Style>
)
Which isn't so bad either 🤔
Svelte's reactivity
Where Svelte shines is its reactivity. Look at all the state management for our app
// this is automatically reactive
let index = 0
// assigning new values in functions triggers re-renders
function nextMovie() {
index = (index + 1) % MarvelMovies.length
}
function prevMovie() {
index = index - 1
if (index < 0) {
index = MarvelMovies.length - 1
}
}
Define a variable, index
, change it inside methods. When its value changes, the component re-renders.
😍
As far as I understand, Svelte is smart enough to re-render only the HTML nodes that rely on the index
variable. Sort of like what you can achieve with MobX and React if you're super careful.
This does seem easier than React's setState
. Less to think about.
However, reactivity can come to bite you in the butt with more complex apps. Sometimes it leads to an effect like screen tearing where parts of the UI update before everything is ready.
Imagine if instead of changing index
, each button click changed title
, image
, and description
separately. You might get each part of the UI updating on its own without waiting for all 3 to finish changing.
For that, Svelte comes with a built-in dispatcher. I haven't used it, but looks like it gives you functionality similar to Redux.
Svelte's event handling
Another neat Svelte feature is the event handling.
Svelte uses what I believe are called directives. thing:something
syntax added to the HTML. Remember when I said there's no such thing as plain HTML in modern JS? 😛
We used the on:
directive to make buttons work
<button on:click="{prevMovie}" style="grid-area:b1">👈</button>
Call the prevMovie
function when the button is clicked.
That's it. No binding. No passing params. No nothing. Svelte figures it all out on its own.
Svelte's template logic
This is where I think Svelte fumbles. Svelte's template logic is easy to use, but reminiscent of old Mustache or Handlebars syntax.
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}
Not sure how I feel about that 🤔
Easy to read, yes, easier to write than React's nested ternary expressions, definitely, but means you have to learn another syntax beyond JavaScript, CSS, and HTML. Which can be good or bad.
Depends what you're doing I guess. For simple stuff this is great.
The verdict?
Svelte is great. Quick to get started, easy to use, good ergonomics, not too complex. Like other frameworks, I'd have to build some bigger projects to see how it feels in the real world.
That's where I've found in the past that React shines. With bigger more complex projects. Whereas Vue, in my experience, is quick to get started but breaks down with complexity.
Svelte? I don't know yet.
But it feels like Svelte takes the best of React and the best of Vue to make something awesome.
I recommend you dig through the examples. They're great and show off Svelte's best features.
Like the built-in transition support. Love it 👌
Continue reading about Svelte takes the best of React and the best of Vue to make something awesome
Semantically similar articles hand-picked by GPT-4
- Just for fun 👉 React vs. jQuery vs. Svelte, same 🐱 app
- Livecoding 52: First impressions of Vue
- Why dataviz does better for your career than TODOapps
- Your first NextJS app – CodeWithSwiz
- Why CSS-in-JS is winning, an example
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️