StackOverflow 2021/22 survey voted Svelte the most liked framework, not counting server-side frameworks. However, the ecosystem behind it is not as large as that of React and the meta-framework choice is scant, too. React has remix, gatsbyjs, and next behind it, which is to say if you’re not only interested in making front-end components, you’ll still like the developer experience, but the user experience will suffer.
Svelte is the first framework to adopt the approach of acting as compile/bundle step processor rather than the component runner in the users’ browser, resulting in unique benefits like simple bundling, performance that beats no framework javascript, simple reactive model, and smaller bundle size.
By eliminating the need to be shipped within a bundle, Svelte no longer has to consider and compromise between developer experience and features against library size. It also compiles to and is compatible with web components. It has meta frameworks like Elder js and Svelte Kit/Sapper. Elder js is novel, like Svelte, Static Site Generator (SSG) meta-framework that competes against React with gatsbyjs and bests them in time to interactive times during user page load with SEO in mind. Sapper is outdated, but Svelte Kit- in beta- is the successor to it. Therefore it doesn’t currently, (in early 2022), have a competitive Server-Side Rendered (SSR) framework.
Here’s what reactivity and component look like in Svelte, taken straight from svelte playground:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<
button on: click = {
handleClick
} >
Clicked {
count
} {
count === 1 ? 'time' : 'times'
}
</button>
This component will weigh in at about 20kb because Svelte will only ship bindings between event handlers to ultimately the count text. Synthetic events or virtual DOM like in React might exist before the compile step for a better developer experience, but not in the user’s browser. It is also faster at re-rendering without the virtual DOM. For example, you can write if/else directly within the template. When using loops, you don’t need ids.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script>
let count = 0;
//Turn size into a computed property, script/dom isn't rerun between every rerender
//So updating state/count isn't enough to update values of computations
$: size = Array.from({length: count})
function handleClick() {
count += 1;
}
</script>
<
button on: click = {
handleClick
} >
Clicked {
count
} {
count === 1 ? 'time' : 'times'
}
</button>
//putting Array.from({length: count}) directly in place of size also works
{
#each size as be, i
} {
#if i % 5 == 0
}
<br>
{/if}
I
{/each}
In the above code, there was a statement behind $:
, which acts like didUpdate and useEffect in that it’s reactive. A reactive statement referencing a reactive variable will rerun should the variable change. Reactivity annotation may be applied to a code block as $:{if(true) null }
. There isn’t a reactive system without caveats or much ceremony. For example, the reactive statement may not run as much as you think. It won’t support recursion even if you read and change the same reactive value from within the same block. It won’t react to any reassignments that come after a reactive statement because the statement has already run, and like with recursion, it won’t rerun during the same tick. Svelte stores and fixes these issues through global state management and will not operate within the constraints of ticks.
Unlike the local variables, the store requires a bit more ceremony, with calls like update and set, but it then takes extra arguments for granular reactivity controlling when reruns occur despite reference changes. There are other caveats like specifics about how reactive statements begin running if they lose track of reactive dependencies used within a statement or block or reactive value change detection (but it is nowhere as bad as React).
Svelte props work by declaring them in child as export let propName
, and passing them in through parent as <TheComponent propName={propName} propName2=”static” />
.