Svelte vs Vue

A side-by-side comparison of Vue and Svelte!

These days, it seems like a new JavaScript framework pops up every six months, each one claiming to be even more revolutionary than the last. This has created a sort of ‘battle’ of the frameworks, the most popular being Vue, React, and Angular. However, Svelte, an even newer framework, has been gaining popularity and making waves in the web development world. Svelte is known for being faster than most other frontend frameworks due to its novel approach to building user interfaces. In a nutshell, Svelte is not actually a framework, but rather a compiler. Technically speaking, Svelte code is not JavaScript. The compiler takes the Svelte code as an input and uses it to generate the actual JavaScript code, eliminating the need to deploy a library (like we do with other frontend frameworks). I’ve been a loyal Vue developer for the past two years, but hearing about Svelte piqued my interest and got me asking the same thing you’re probably wondering right now: is Svelte the next big thing? Is it even better than Vue and should I be making the switch right now? Well, I’m here to get to the bottom of that and provide you with some answers.

What is Svelte?

Similar to Vue, Svelte is a lightweight component-based framework that allows JavaScript developers to write organized, easy-to-read code. However, unlike Vue, it does not utilize the virtual DOM, requires fewer lines of code, and is truly reactive.

Less Code

Every developer wants to achieve their goal with as few lines of code as possible. Less code saves time, reduces bugs, and improves readability. Let’s look at a simple ‘Hello, World!’ example and compare it to Vue.

Svelte Code:

<script>
	let text = 'World';
</script>

<div>
	<h1>Hello, {text}!</h1>
</div>

Vue Code:

<script>
	export default {
		data() {
			return {
				text: 'World'
			};
		}
	};
</script>

<div>
	<h1>Hello, {{ text }}!</h1>
</div>

Similar to Vue, Svelte uses templates and single file components, however, you can typically achieve the same result with fewer lines of code due to the lack of boilerplate necessary. In the Svelte example, notice how any variable declared is automatically reactive and can be used in the markup with single curly braces: {text}.

True Reactivity

According to Rich Harris, the creator of Svelte, “Svelte 3.0 moves reactivity out of the component API and into the language.” So what does this mean? As we’ve already covered, Vue (and most other JavaScript frameworks) relies on an API to tell it when data changed in order to know when to update the Virtual DOM. This means that the reactivity of the framework is tied to a specific API. Without this API, it would be completely unaware when there are changes to the data.

Svelte takes a unique approach to this. Rather than running your code top to bottom, it runs it in topological order. The compiler takes all the variables in the Svelte code and creates a dependency graph of who needs who first. In simple terms, if statement A relies on statement B, then statement B will run first regardless of the order in which they are declared. This allows us to then bind variables and achieve true reactivity!

No Virtual DOM

Today all of the popular frameworks use what is known as the Virtual DOM. The Virtual DOM can be thought of as a copy of the original DOM, which can be easily manipulated and updated without using the DOM APIs. The Virtual DOM can then act as a ‘blueprint’ to make specific changes to the original DOM in a targeted and optimized way. But this does not come without performance penalties. What if we could know how things would change in an app at build time, rather than waiting until run time to do the work?

Unlike other frameworks, rather than using the virtual DOM, Svelte takes your components and compiles them into a single vanilla JavaScript bundle that updates the DOM whenever state changes. This means that when your program is running in the DOM, no overhead framework code is injected in the browser, resulting in a faster website. In fact, Svelte is known as the ‘disappearing framework’ because it is not present after the build process.

Getting started with Svelte

As previously mentioned, Svelte is a novel type of framework that acts as a compiler, making getting started a little bit confusing at first. Rather than adding it to your app with import or require (as you do with Vue), the easiest way to get started with Svelte is to download or clone the template from https://github.com/sveltejs/template. You can easily do this with the following commands.

First, you need to have digit installed globally. To install it run: npm i digit -g

npx degit sveltejs/template svelte-app
cd svelte-app
npm install

This will download a basic template from Svelte’s GitHub account. We can then start up a development server using the following command:

npm run dev

This will serve your app on localhost and rebuild it with Rollup every time you make a change.

Svelte Basics

Reactive Variables

First, let’s talk about how to create reactive variables with Svelte. Unlike Vue, this is done without any special API functions. Simply define them as you would for regular JavaScript variables.

<script>
let userName = ‘Steph Dietz’;
let userAge = 25;
const clearName = () => {
userName = ‘’;
};
</script>

While userName may look like a primitive JavaScript variable, it actually behaves more like an observable. So whenever you reassign the variable, the component will get re-rendered. In the above example, calling clearName will reassign userName, which will cause the component to be re-rendered.

Computed Values

In frontend development we frequently need to create state that is dependent on other variables, and automatically updates when these variables change. For this situation, Svelte has reactive declarations, which looks like this:

$: userInfo = userName + 'is' + userAge + ‘years old.;

In this example we define userInfo, which is dependent on two other values, userName and userAge. In order to do this, we use a signature element in the Svelte syntax, the dollar sign, which tells Svelte to re-run this code anytime a referenced value changes. So in the above example, userInfo will update anytime userName or userAge changes. Without using the dollar sign, userInfo will not be updated after the initialization. This is very similar to Vue’s computed properties. Let’s look at a side-by-side comparison of the two.

Svelte Code:

<script>
	let userName = 'Steph Dietz';
	let userAge = 25;
	$: userInfo = userName + 'is' + userAge + 'years old.';
</script>

Vue Code:

<script>
	export default {
	data() {
	return {
	userName: 'Steph Dietz',
	userAge: 25

	},
	computed: {
	userInfo() {
	return this.userName + 'is' + this.userAge + 'years old.';
	}
	}
	}
</script>

The most noticeable difference is that Svelte uses fewer lines of code to achieve the same result, as we’ve already covered. Another important difference is that Vue requires you to use the keyword this, which is necessary in order to access all of your data in the Vue instance. With Svelte, we already have access to all state defined in the component.

Element Directives

Svelte’s template syntax is extremely similar to that of Vue’s and has many similar element directives. Let’s compare how we would respond to input events and click events for each.

Svelte Code:

<script>
	let userName = 'Steph Dietz';
	let userAge = 25;
	$: userInfo = userName + 'is' + userAge + 'years old.';
	const clearName = () => {
		userName = '';
	};
</script>

<div>
	<input bind:value={userName} type="text" />
	<input bind:value={userAge} type="number" />
	<button on:click={clearName}> Clear Name </button>
	<div>{userInfo}</div>
</div>

Vue Code:

<script>
	export default {
	data() {
	return {
	userName: 'Steph Dietz',
	userAge: 25

	},
	computed: {
	userInfo() {
	return this.userName + 'is' + this.userAge + 'years old.';
	}
	}
	methods: {
	clearName() {
	this.userName = '';
	}
	}
	}
</script>

<div>
	<input bind:value={userName} type="text" />
	<input bind:value={userAge} type="number" />
	<button on:click={clearName}>Clear Name</button>
	<div>{userInfo}</div>
</div>

Take a look at the inputs in the example above. In each case, we want to bind the value of the input with the value of userName and userAge, respectively. Thankfully, both Vue and Svelte have a way of expressing the binding rather than responding to the input event ourselves. Vue uses the v-model directive while Svelte uses bind:value. Using these directives binds the input value to the specified data value. So in our example, as the value in the first input changes, so does userName. As a user types in either input, the computed property userInfo will be updated, and the component will be re-rendered, displaying the updated value in our HTML.

Another important directive available for both Vue and Svelte is the on: directive. In the above Svelte example, we use on:click to call the clearName function, which updates our userName to an empty string. With Vue, we are able to replace on: with its shorthand @. When it comes to element directives, the difference between Vue and Svelte is minimal.

List Rendering

The need to display list items is an extremely common occurrence in front-end applications. Vue has a core directive, v-for, which makes rendering lists of items onto the browser extremely simple. Svelte has a similar way of iterating over lists of values using an each block, {#each … }. Here is an example of how it is used.

{#each expression as name}...{/each}

You can use each blocks to iterate over any array or array-like value (i.e. any object with a length property). An each block can also have an {:else} clause, which is rendered if the list is empty.

Svelte Code:

<script>
	let users = [
		{ name: 'Steph', age: 25 },
		{ name: 'Rob', age: 27 },
		{ name: 'Mike', age: 28 }
	];
</script>

<div>
	{#each users as user}
		<div>
			<p>{user.name} is {user.age} years old.</p>
		</div>
	{/each}
</div>

Vue code:

<script>
export default {
data() {
return {
let users = [
{name: 'Steph', age: 25},
{name: 'Rob', age: 27},
{name: 'Mike', age: 28}
]

}
}
</script>
<div v-for="user in users">
<p> {user.name} is {user.age} years old. </p>
</div>
</div>

As you can see, list rendering is extremely similar between Svelte and Vue. The most important difference to point out is that in Vue, you define your alias for the array element before the source data array, while the opposite is true for Svelte. Also, Svelte requires an end tag, {/each}, while Vue does not.

Components

Components are reusable instances that we can use as custom elements inside our HTML. This allows us to reuse code rather than constantly repeating the same few lines. Part of what makes Vue such a powerful framework is the simplicity when creating and using components.These components can store all the needed code (HTML, CSS, and JavaScript) in a single file. What makes these components even more powerful is that they are dynamic. You can easily pass data in using the custom prop attribute and emit data using $emit. Similarly, Svelte gives us the ability to create single page components and allows us to pass data in and out in a slightly different way. Let’s look at how we would create a simple input component using each.

Svelte Code:

<script>
	import TopNav from './TopNav.svelte';
	let title = 'Enter your name below.';
	let name;
	const submitForm = () => {
		console.log('Submitted!');
	};
</script>

// App.svelte
<div>
	<h1>Hello, {name}</h1>
	<TopNav {title} submit={submitForm} bind:name />
</div>
<script>
	export let title;
	export let name;
	export let submit = () => {};
</script>

// TopNav.svelte
<div>
	<h1>{title}</h1>
	<input bind:value={name} type="text" />
	<button on:click={submit}> Submit </button>
</div>

Vue Code:

<script>
	import TopNav from './TopNav.svelte';
	export default {
	data() {
	return {
	title: 'Enter your name below.',
	name: ''

	},
	methods: {
	submitForm() {
	console.log('Submitted!');
	}
	}
	}
</script>

// App.vue
<div>
	<h1>Hello, {name}</h1>
	<TopNav :title="title" @submit="submitForm()" v-model="name" />
</div>
<script>
	export default {
		props: ['title', 'bame']
	};
</script>

// TopNav.vue
<div>
	<h1>{title}</h1>
	<input v-bind:value="name" v-on:input="$emit('updateName', $event.target.value)" type="text" />
	<button @click="$emit('submit')">Submit</button>
</div>

As you can see in the above example, we have to import our component for both frameworks, but Svelte does not require you to register it like we do with Vue. After importing, it is automatically available for use in our HTML. Svelte also has a unique way of passing data between components. Rather than using the prop attribute to pass in data, we expose the variable to our parent component using export:

<script>
	export let title;
</script>

We are then able to pass a value from our parent component to our child like this:

<component title=”My Title”>

Here, we can pass in a static string, or we can use single curly braces to pass in another variable available in our parent component. This gives us one way binding: our parent component can pass data to our child component, but what if we want two way binding? We can do this using bind:value. We still expose our value from the child component, and in our parent component we say:

<script>
	let parentTitle = 'New Title';
</script>

<component bind:title={parentTitle} />

Here, title is the name of the value exported in our child component and we are using bind: to bind it to parentTitle in our parent component. Now, title and parentTitle will always be the same value. This means if you update title in the child component, parentTitle in the parent component will be updated as well, and vice versa. Lastly, let’s go over how to communicate click events from the child component to the parent. We can do this by encapsulating the parent’s state brackets and passing it down to the child component that triggers it when needed. Let’s set up our child component like this:

<script>
	export let submit = () => {};
</script>

<button on:click={submit}> Submit</button>

Here we are exposing our submit function from the component. This means that we can pass a property submit to the component from our parent that has the desired functionality. If we add this to our parent component:

<script>
	let submitted = false;
	let submitFromParent = () => {
		submitted = true;
	};
</script>

<component submit={submitFromParent} />

Then when we click the button in our child component, our submitFromParent method will run and update the value of submitted.

Learning Curve

When writing Svelte code, it feels like writing normal JavaScript and the template syntax is extremely similar to Vue, making the learning curve almost non-existent. I think any experienced JavaScript developer will have no issue learning Svelte as it is very intuitive. The Svelte documentation is detailed and expansive, providing all the necessary information. In addition, there is already a lot of other content providing additional examples, tutorials and discussions. I was able to pick up Svelte in less than a day, and I am confident most developers will be able to do the same.

Cons

So far Svelte seems equal or superior to Vue in many ways, but it does have its drawbacks. As I already mentioned, Svelte is not technically JavaScript, which may be a problem in certain unique situations. Svelte is a DSL (domain specific language) that looks like JavaScript, and it has to be compiled to be useful. Why does that matter? If it works in its own way, why should we care that it isn’t JavaScript? Well, most of the time we probably won’t, but there are edge cases. For example, if you were expected to develop a JavaScript app using only a code editor and a browser, you wouldn’t be able to use Svelte at all because you have to install a compiler before you can develop Svelte. In contrast, you can still use runtime-based frameworks like Vue. While the above issue is not likely to occur in practice, one thing that makes Vue a more attractive option to developers is its abundance of community support, tools, and Vue specific libraries. The lack of community may negatively impact your development as you may not have access to specific libraries and plugins that are available for Vue. However, Svelte is still pretty new and is quickly gaining popularity, so this will likely not be an issue in the near future.

Conclusion

I think Svelte is one of the better things to happen to front-end development in a while. The concept behind Svelte and its execution enables us to do more, while shipping less. I think we will not only see a lot of developers switch to Svelte in the future, but I also think Vue and other popular frameworks will start adapting some of Sveltes concepts. So should you make the switch today? It depends. If you will need to add developers to your team in the near future, probably not, as Svelte developers may be more difficult to come across. Also if you are building a complex app that will require specific libraries/ plugins, Svelte may not be the best option as of right now. If you don’t fall into either of those categories then I think now is the perfect time to make the switch! I see Svelte becoming one of the leading frameworks within the next couple of years, so get a head start!

Email: steph.dietz@vercel.com