Published 01-31-2023
In June of 2022, I became curious (and frustrated) enough to give something new a try. — That something was Svelte(Kit).
I had been working on Enterprise applications in Angular for years, and so I always wrote my side projects in Angular as well.
One weekend, I was hell-bent on improving my lighthouse score and speeding up the apps initial page load.
I spent hours refactoring, lazy loading, removing dependencies. After everything I tried, my scores were still far from ideal in production.
This article is not to say that Angular can’t be fast. That’s not true. It’s that Svelte Kit makes it intuitive to be fast.
Svelte with SvelteKit promotes Server Side Rendering
out of the box and built in. They provide tools and conventions to intuitively determine when you’re in the context of server side rendering vs client side rendering.
For example, everything on this page that is not dynamic, is server side rendered. We display a shell of our component immediately on the initial load, and then populate the dynamic content on the client.
<script>
import { onMount } from 'svelte';
let photos = [];
onMount(async () => {
const res = await fetch(`/tutorial/api/album`);
photos = await res.json();
});
</script>
<div class="photos">
{#each photos as photo}
<figure>
<img src={photo.thumbnailUrl} alt={photo.title}>
<figcaption>{photo.title}</figcaption>
</figure>
{:else}
<p>loading...</p>
{/each}
</div>
Why Server Side Rendering: A simple explanation is that going from Server --> Client
is faster than Server --> Client --> Server --> Client
Another way of looking at this is that traditional SPA frameworks, like Angular, must pull down and parse/execute some javascript before displaying anything on the screen.
With SSR, the server sends rendered HTML on first load and then hydrates it. This keeps the initial page load very fast.
Just about every framework comes with some implementation of lazy loading
.
Svelte leverages Vite which makes lazy loading intuitive & practically automatic.
For example, a component or page’s dependencies won’t be loaded until that component/page is created. So, by only importing what we need, we’re effectively lazy loading everything else.
<script>
// OKAY
import Fa from 'svelte-fa';
import { faUserGroup } from '@fortawesome/free-solid-svg-icons/faUserGroup';
import { faClock } from '@fortawesome/free-solid-svg-icons/faClock';
// AVOID
import { DatabaseClient } from '@supabase'
</script>
<div>
Really simple landing page
<Fa icon={faUserGroup}/>
<Fa icon={faClock}/>
</div>
Svelte can prerender
a page. Any content that is not dynamic (the same to all users), can be prerendered. Prerendering computes the contents of a page at build time and saving the HTML for display. i.e. we don’t recompute the page for each visitor and instead do the computation during build time.
It’s as easy as setting a variable in our +page.ts
export const prerender = true;
Again, other frameworks can achieve this. It’s more so how easy and intuitive svelte(kit) makes it.
Svelte just ships less javascript. And (imo) makes it easier to write apps with less code / boilerplate.
Comparing the size of the packages. Svelte is significantly smaller.
Caveat. Not a totally fair comparison, Angular brings a lot, and by contrast this doesn’t include kit. However, Angular brings on a lot of overhead. And claims that svelte has to pull in a bunch of separate libraries is not necessarily true. This is because it uses native web apis where possible and provides things like store.
Svelte Kit makes it intuitive to write code on the server as well. The experience of moving code out to the server, even as a frontend developer, is relatively easy. Which means less code on the client.
export async function PUT(all) {
const request = all.request;
const theme = await request.text();
all.cookies.set('theme', theme, { path: '/' });
if (!theme) {
return {
status: 400,
body: missingThemeErr(theme)
};
}
return new Response(null, {
headers: { 'Set-Cookie': `theme=${theme}; SameSite=Strict; HttpOnly; Secure` }
});
}
function missingThemeErr(theme: string) {
return `${theme} theme could not be found!`
}
Summary
Here’s the numbers from which this post is based on. The bad ones are after extensive refactoring, lazy loading, and changes. It’s a small NX project with a couple of Angular/Firebase applications.
The 100s are a rewrite of the app using Svelte Kit.