Svelte 5
Svelte 5 was officialy released in October, introducing runes to a bit contraversy, some saying svelte has become react, how dare they, but that’s quite a bit off the mark.
There are quite a few changes in svelte 5 as it was a ‘ground-up rewrite’.
Runes
$state, $derived, $effect among others, utilising signals, they allow fine grained reactivity and remove some of the common issues when using ‘$:’ Initially the community was not happy with the concept of runes but upon reflection it provides a clearer and more explicity api when working with state.
$state
Allows you to create a new reactive property, that can be read and updated in a more performant manner than the old observable wau, it just returns a property which can be used as normal.
$derived
is like a computed expression, its value will be updated when any referenced state changes.
let val = $state(0)
let total = $derived(val * 2)
$derived.by
Allows you to derive a value from a function, and it is updated when any referenced state changes.
$effect
is similiar to useEffect in react land, and similiarily can be a bit of a footgun as it’s never clean when it will run.
Event handlers
Instead of svelte specific event handlers like on:click
, they now use the regular javascript way like onclick
, removing a framework specific way for a standard is a win.
Props
There is now a specific prop method rather than the non standard use of export.
let { class: klass, ...rest } = $props();
Slots
Are gone in place of snippets, allowing you to pass multiple components as props.
<script>
let { children } = $props();
</script>
{@render children?.()}
Upgrading
Conveniently the svelte team have provided a smooth upgrade path, older svelte 4 applications should just work on v5, they have also created a new cli tool to automatically migrate your exisiting svelte 4 application to svelte 5.
I have an existing svelte kit application that uses svelte 4, so lets upgrade it.
We can run the new cli tool upgrade the dependencies and code changes to new svelte 5 apis
npx sv migrate svelte-5
The migration script changed a ton of files:
- export let stats;
+ let { stats } = $props();
Updating props for the new props method.
let leagues = [];
to
let leagues = $state([]);
Updating observable properties for the new state rune.
Run
In place of the old $: syntax was a method run
used where svelte cant safely convert to a rune.
$: if(event) {
if(event.Eps === ’NS’) {
status = parseStartTime(event.Esd)
} else {
status = event.Esd
}
}
to
run(() => {
if(event) {
if(event.Eps === ’NS’) {
status = parseStartTime(event.Esd)
} else {
status = event.Esd
}
}
})
It most cases this can easily be converted to use derived.by
, which takes a function and returns a value, in this case the new status.
let currentStatus = $derived(event?.Eps === 'NS' ? parseStartTime(event.Esd) : event.Eps);
Stores
Svelte provides a simple store contract allowing you to create global state or state outside components, but this is now not the recommended way, now you can use runes outside components inside .svelte files.
export const data = $state(0)
You cannot just export your state and update it from a component.
<script>
import {data} from "./store.svelte.js"
</script>
<h1>Hello {datal}!</h1>
<button onclick={() => data++}>Update</button>
Setting the value won’t work as it is simply a number and is not trackable by svelte.
We have a few different ways we can get around this.
Object
export const appData = $({ val });
Functions
const data = $state(0)
export function setValue(value) {
data = value
}
export function readValue() {
return data
}
Classes
export class AppData {
val = $state(0)
}
Using a class automatically adds a getter and setter for the val property.