

Svelte for Angular Developers
source link: https://www.tuicool.com/articles/UrYZJvR
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

A simple introduction to Svelte from an Angular developer’s perspective
Jul 24 ·10min read
Svelte is a relatively recent framework for building UIs developed byRich Harris, also the creator of Rollup.
Svelte will likely appear as a radically different approach from what you’ve seen before, and that’s probably a good thing.
Svelte will impress you for mainly two things: its speed, and its simplicity . In this article, we’ll focus on the latter.
As my main expertise revolves around Angular, it is only normal that I try to learn it by replicating the approaches I’m used to with the former by using Svelte. And this is what this article is going to be about: how to do Angular things — but with Svelte.
Useful tip:Use Bit to encapsulate components with all their dependencies and setup. Build truly modular applications with better code reuse, simpler maintenance and less overhead.
Note: Although I will be expressing my preferences, this is not a comparison: it is a simple and quick introduction to Svelte for people who use Angular as a framework of choice.
Spoiler Alert: Svelte is fun.
Components :package:
In Svelte every component corresponds to its relative file: for instance, the component Button
will be created by naming its file Button.svelte
. Of course, we normally do the same in Angular, but it is purely a convention.
Svelte components are written using a single-file convention, and it is made of 3 sections: script
, style
, and the template, which doesn’t have to be wrapped within its specific tag.
Let’s create a dead-simple component that renders “Hello World”.
Importing Components
This is mostly the same as if you were importing a JS file, with an only difference:
.svelte script
<script>
import Todo from './Todo.svelte';
</script><Todo></Todo>
:bulb:It is clear from the snippets above that the number of lines to create a component in Svelte is incredibly low . There’s a lot of implicitness and constraints there, of course, yet it is simple enough to get quickly used to it. Nicely played.
Basic Syntax :closed_book:
Interpolations
Interpolations in Svelte are more similar to React than they are to Vue or Angular:
<script> let someFunction = () => {...}</script><span>{ 3 + 5 }</span> <span>{ someFunction() }</span> <span>{ someFunction() ? 0 : 1 }</span>
I am quite used to typing twice the curly brackets that sometimes I make simple mistakes, but that’s just me.
Attributes
Passing attributes to components is also fairly easy, there’s no need for quotes and can even be Javascript expressions:
// Svelte
<script>
let isFormValid = true;
</script><button disabled={!isFormValid}>Button</button>
Events
The syntax for listening to events is on:event={handler}
.
<script>
const onChange = (e) => console.log(e);
</script><input on:input={onChange} />
As you may notice, opposite to Angular we don’t need to call the functions using parenthesis. To pass arguments to the function with could simply define an anonymous function:
<input on:input={(e) => onChange(e, ‘a’)} />
In terms of readability, I am in two minds:
- typing less, as we do not need brackets and quotes, is always a good thing
- readability-wise, I always liked Angular better than React, and as a result, to me is slightly more readable than Svelte. With that said, once again, I am very used to it and therefore my view here is biased
Structural Directives
Contrary to Vue and Angular, Svelte provides a special syntax for looping and control flow within templates rather than using structural directives:
{#if todos.length === 0}
No todos created
{:else}
{#each todos as todo}
<Todo {todo} />
{/each}
{/if}
I like this a lot. No need to create HTML nodes, and readability-wise it does look awesome. Unfortunately my Macbook’s UK keyboard places # in a difficult to-reach-spot, which is making my experience with it a bit clunky.
Inputs
Setting and getting properties (or @Input
) from other components is as easy as exporting a constant from a script. Alright, that can be confusing — let’s write an example and see how easy it is:
<script>
export let todo = { name: '', done: false };
</script><p>
{ todo.name } { todo.done ? ':white_check_mark:' : ':x:' }
</p>
- As you may have noticed, we initialized
todo
with a value: that will be the default value if the consumer will not provide a value for the input
Next, we create the container component that will pass the data down:
<script>
import Todo from './Todo.svelte'; const todos = [{
name: "Learn Svelte",
done: false
},
{
name: "Learn Vue",
done: false
}];
</script>{#each todos as todo}
<Todo todo={todo}></Todo>
{/each}
Similarly to plain JS, todo={todo}
can be shortened and written as follows:
<Todo {todo}></Todo>
At first, I thought it was crazy, and now I think it is genial.
Outputs
To create an @Output
, i.e. a notification from child components to their parents, we will be using Svelte’s createEventDispatcher
.
- We import the function
createEventDispatcher
and assign its return value to a variable calleddispatch
- We call
dispatch
with two arguments: its name, and its payload (or “detail”) - Notice : we add a function on click events (
on:click
) that will call the functionmarkDone
<script>
import { createEventDispatcher } from 'svelte'; export let todo;
const dispatch = createEventDispatcher();
function markDone() {
dispatch('done', todo.name);
}
</script><p>
{ todo.name } { todo.done ? ':white_check_mark:' : ':x:' }
<button on:click={markDone}>Mark done</button>
</p>
The container component will need to provide a callback for the event dispatched, so that we can mark that todo object as “done”:
- we create a function called
onDone
- we assign the function to the component’s event that we called
done
.
The syntax ison:done={onDone}
<script>
import Todo from './Todo.svelte';
let todos = [{
name: "Learn Svelte",
done: false
},
{
name: "Learn Vue",
done: false
}];
function onDone(event) {
const name = event.detail;todos = todos.map((todo) => {
return todo.name === name ? {...todo, done: true} : todo;
});
}
</script>{#each todos as todo}
<Todo {todo} on:done={onDone}></Todo>
{/each}
Notice: to trigger a change detection , we do not mutate the object . Instead, we reassign the array todos
and replace the todo marked as done.
:bulb: That is why Svelte is considered truly reactive : by simply reassigning the variable, the view will re-render accordingly.
ngModel
Svelte provides a special syntax bind:<prop>={value}
for binding certain variables to a component’s attributes and keep them in sync.
In different words, it allows for two-way data binding:
<script>
let name = "";
let description = ""; function submit(e) { // submit }
</script><form on:submit={submit}>
<div>
<input placeholder="Name" bind:value={name} />
</div> <div>
<input placeholder="Description" bind:value={description} />
</div> <button>Add Todo</button>
</form>
Reactive Statements :rocket:
As we’ve seen before, Svelte reacts to an assignment and re-renders the view. To react to a change from another value, we can use reactive statements so that another value can automatically change in its turn.
For instance, let’s create a variable that will display whether all the todos
have been checked:
let allDone = todos.every(({ done }) => done);
Unfortunately, though, the view will not be rendered because we never reassign allDone
. Let’s replace this with a reactive statement, that makes us of Javascript “labels”:
$: allDone = todos.every(({ done }) => done);
Oh! That’s exotic. And before you shout “that’s too magic!”: did you know that labels are valid Javascript ?
Let’s take a look at a demo:
Content Projection
Content Projection also uses slots, which means you can name a slot and project it wherever you want within your component.
To simply interpolate all the content passed as content to your component, you can simply use the special element slot
:
// Button.svelte
<script>
export let type;
</script><button class.type={type}>
<slot></slot>
</button>// App.svelte
<script>
import Button from './Button.svelte';
</script><Button>
Submit
</Button>
As you can see, the string “Submit” will take the place of <slot></slot>
. Named slots require us to assign a name to a slot:
// Modal.svelte
<div class='modal'>
<div class="modal-header">
<slot name="header"></slot>
</div>
<div class="modal-body">
<slot name="body"></slot>
</div>
</div>// App.svelte
<script>
import Modal from './Modal.svelte';
</script><Modal>
<div slot="header">
Header
</div>
<div slot="body">
Body
</div>
</Modal>
Lifecycle Hooks
Svelte provides 4 lifecycle hooks, that are imported from the svelte
package.
- onMount , a callback that runs when the component gets mounted
- beforeUpdate , a callback that runs before the components updates
- afterUpdate , a callback that runs after the components updates
- onDestroy , a callback that runs when the component gets destroyed
onMount
is a function that accepts a callback that will be called when the component is mounted on the DOM. In short, it can be associated to ngOnInit
.
If you return a function from the callback, this will be called when the component is unmounted.
<script>import { onMount, beforeUpdate, afterUpdate, onDestroy } from 'svelte';onMount(() => console.log('Mounted', todo)); afterUpdate(() => console.log('Updated', todo)); beforeUpdate(() => console.log('Going to be updated', todo)); onDestroy(() => console.log('Destroyed', todo));</script>
:bulb:It’s important to notice that when onMount
is called, its inputs have already been initialized. That means, todo
is already defined when we log it in the snippet above.
State Management
State Management is Svelte is incredibly fun and easy, and probably the aspect I like the most about it. Forget Redux’s boilerplate, and let’s see how to build a store that will allow us to store and manipulate our todos.
Writable Store
The first thing we can do is to import writable
from the package svelte/store
and pass to the function the initial state
import { writable } from 'svelte/store';const initialState = [{
name: "Learn Svelte",
done: false
},
{
name: "Learn Vue",
done: false
}];
const todos = writable(initialState);
Normally, I’d store this in a file called todos.store.js
and export the writable store so that the container component can update it.
As you may have noticed, todos
is now a writable object and not an array. To retrieve the value of the store, we are going to use some Svelte magic:
- by prepending the store name with
$
we can directly access the value of the store!
:bulb:That means, all the references to todos
will now be $todos
:
{#each $todos as todo}
<Todo todo={todo} on:done={onDone}></Todo>
{/each}
Setting State
A writable store’s state can be set by calling the method set
which will imperatively set the state to the value passed:
const todos = writable(initialState);function removeAll() { todos.set([]); }
Updating State
To update the store based on the current state, in our case the todos
store, we can call the function update
to which we pass a callback. The return value of the callback will be the new state passed to the store:
Let’s rewrite the function onDone
that we defined above:
function onDone(event) { const name = event.detail; todos.update((state) => { return state.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); }); }
Alright, I know, I wrote a reducer in the component. Not cool, you’re saying. Let’s move that to the store file, and export a function that simply takes care of updating the state.
// todos.store.jsexport function markTodoAsDone(name) {
const updateFn = (state) => {
return state.map((todo) => {
return todo.name === name ? {...todo, done: true} : todo;
});
}); todos.update(updateFn);
}// App.svelteimport { markTodoAsDone } from './todos.store';function onDone(event) {
const name = event.detail;
markTodoAsDone(name);
}
Listening to value changes
We can use the method .subscribe
to listen to value changes from a store, . Notice, though, that the store is not an observable although the interface looks similar.
const subscription = todos.subscribe(console.log);subscription(); // unsubscribe subscription by calling it
:bulb: Svelte’s store package also provides two more utilities called readable
and derivable
.
Observables
Oh, the part you were waiting for! You’ll be delighted to know that Svelte recently added support for RxJS and the ECMAScript Observable proposal.
As an Angular developer, I am quite used to working with reactive programming and not having something like the async pipe would be a bummer. But Svelte surprised me once again.
Let’s see how the two can work together: we’ll render a list of repositories from Github searched with the keyword “Svelte”.
You can paste the snippet below in the Svelte REPL and it will just work:
<script>
import rx from "https://unpkg.com/rxjs/bundles/rxjs.umd.min.js";
const { pluck, startWith } = rx.operators;
const ajax = rx.ajax.ajax;
const URL = `https://api.github.com/search/repositories?q=Svelte`;
const repos$ = ajax(URL).pipe(
pluck("response"),
pluck("items"),
startWith([])
);
</script>{#each $repos$ as repo}
<div>
<a href="{repo.url}">{repo.name}</a>
</div>
{/each}// Angular's implementation
<div *ngFor="let repo of (repos$ | async)>
<a [attr.href]="{{ repo.url }}">{{ repo.name }}</a>
</div>
:bulb: As you may have noticed, I prefixed the observable repos$
with $
and Svelte will automagically render it!
My Svelte Wishlist
Typescript support
As a Typescript enthusiast, I can’t help but wish for being able to write typed Svelte. I am so used to it that I keep typing my code, and then have to revert it. I do hope Svelte will soon add support for Typescript, as I suspect it is on everyone’s wishlist should they use Svelte from an Angular background.
Conventions & Coding Guidelines
Being able to render in the view any variable in the script block is both powerful and, in my opinion, potentially messy. I am hoping the Svelte community will be working on a set of conventions and guidelines to help developers keep their files clean and understandable.
Community Support
Svelte is a great project. With more community support such as third-party packages, backers, blog posts, etc. it can take off and become an established, further option to the awesome front-end landscape we’re enjoying nowadays.
Final Words
Although I was not a fan of the previous version, I am fairly impressed with Svelte 3. It’s easy, small (yet exhaustive) and fun. It is so different that it reminds me of the first time when I transitioned from jQuery to Angular, and that’s exciting.
Whatever your framework of choice, learning Svelte will probably take a couple of hours. Once you figured out the basics and the differences with what you’re used to writing, writing Svelte is going to very easy.
If you need any clarifications, or if you think something is unclear or wrong, do please leave a comment!
Recommend
-
37
Short description of the article Angular blogs Websites on JavaScript Development and Angular Development QndA websites on the Angu...
-
44
A comprehensive list of the most awesome Angular tools, extensions, and libraries.
-
10
Why this ‘Test’ work in progress, this page will be updated when more information will be available I’m developing 2 personal websites to publish on the web and I have to improve their SEO. One website is abo...
-
9
This is part 2 of a walkthrough of me learning how to use custom data stores in Svelte. To see the initial setup, please read Part 1 Now that I have...
-
11
Svelte Custom Stores for React Developers: Part 1 02 August 2020 I started building a simple Svelte application that mirrors the application that I wrote for NSS students to learn React. It's called Nashvi...
-
6
An Angular Dev Tries Svelte If you ask anyone who knows me, they would say my f...
-
20
Front-end frameworks popularity (React, Vue, Angular and Svelte) · GitHub Front-end frameworks popularity (React, Vue, Angular and Svelte) Findings: React is by far the most po...
-
8
Comparing Svelte with other well-known frontend frameworks Svelte vs. Angular vs. React vs. Vue — Who Wins? Angular
-
7
探索React、Angular、Vue、Svelte、Qwik、Solid的响应式原理 作者:Echa攻城狮 2023-06-02 16:28:01 Qwik 的独特之处在于它是唯一不需要进行水合的框架。与其他框架不同,Qwik 不需要在启动时执行所有组件来了解状...
-
6
如何分别在Angular、React、Preact、Vue和Svelte中使用Web组件? - netbasal - 极道 Web组件使我们能够建立可重复使用的、可...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK