pixel art of Toronto

Building AdamGreen.Tech: Multi SPAs vs SvelteKit

Image of a building site crane lowering an image onto a webpage

I've got a confession. I've been using Svelte.js for pushing two years now and in all that time, I've never deployed a Sapper.js or SvelteKit project. I don't dislike either (of course Sapper.js is now largely defunct), I've just never deployed one.

The Old (Bad) Way

Instead, for about half a dozen projects, I've built complex multipart Webpack builds. In doing so I've created something akin to a SvelteKit style workflow (sans the Server Side Rendering). Here's an example.

First, we mount a page, using a root component for that page in the same directory e.g. the about page directory has an index.js (the entrypoint) and an Index.svelte (the root component).

import Index from './Index.svelte';

const app = new Index({
    target: document.body,
});

window.app = app;

export default app;

Assuming we place all these page directories in a single directory, src/pages, we can essentially write a file system call to get the name of each folder with an index.js. I'll call this function getListOfPages() and it essentially spits out a json object like

{
  index: './src/pages/index/index.js',
  about: './src/pages/about/index.js',
  contact: './src/pages/contact/index.js'
  // ...
}

In Webpack, you can have multiple entries as long as the outputs each have a unique name so we write config like this

entry: getListOfPages(),
output: {
  path: path.resolve(__dirname, './build'),
  filename: `[name].[hash].js`
}

The result is essentially a Multi-SPA application. At which point I can hear the howls and cries of people talking about search engine optimisation, shared components across pages, and that you're loading the same Javascript again across multiple pages and not making the best use of caching. And you're right! I know!

A slightly better (but more complicated) Webpack config is possible, and I have written one previously. Essentially you build your component library separately and hierarchically (global components, sectional components, and page-specific components) as a kind of imported javascript library and separate chunk that each entry pulls in depending on need).

At the end of the day though it boiled down to one simple fact: when one page on your site is one Svelte.js SPA, it ends up being bloody tiny (~40kb min + gzip, 160kb raw). Shove a decent size picture on there in an old format (jpg, png, etc.) and you blow 10 times that data without batting an eyelid. At the end of the day, it came down to pragmatism vs ideology. I knew and understood Webpack and can configure it easily to fit a development pattern that produces essentially tiny self-contained SPAs.

But what about SEO? Well, the simple answer is this approach isn't great. Google is pretty good at running Javascript but there are plenty of bots (cough Facebook and Twitter cough) that don't. The applications thus far though were ones where SEO wasn't a primary consideration. For example, these were mostly apps where users had already hit an independently developed landing page and were now looking to login/signup to use services and features with the app. Again, pragmatically, SEO considerations just didn't factor in.

The way

In a lot of ways, SvelteKit basically does the same thing. There are obvious and dramatic differences though. In the standard SvelteKit approach, the end result is not a bunch of javascript and extracted CSS files, which are imported by hollow HTML files. Instead, SvelteKit generates a node webserver and a bunch of javascript files representing each page. Each javascript file is then executed by the server to produce an initial HTML file that can be sent to the client.

This has its advantages; SvelteKit lets you pull any data your front-end view needs server-side and populate the HTML before it hits your client. This is useful for bots that won't execute Javascript and thus conclude your site is nothing but an empty HTML document. It also has the effect of making the load speed feel especially fast, no javascript execution has to take place on the client, beyond the code that makes the front end dynamic.

AdamGreen.Tech was the first time we've deployed a SvelteKit application in a live environment and the results are noticeable. For a rough and ready idea of load-speed and total cumulative layout shift, I use GTMetrix to analyse load speed, and this approach achieves a 98/100 on load speed and a 0.04 on cumulative layout shift.

More than that, effective savings in load times, and time-to-useability gives you more breathing room in the creative elements you deploy on a site. An example is the giant parallax image of Toronto in the background of the site. This image - the largest asset loaded on the page - doesn't hamstring the load times as much because the rest loads so fast.

Put simply, SvelteKit has formalised a very opinionated approach to building front-end experiences that load fast, are easy to maintain but also look slick and can be applied across a variety of different web applications.

Author:

Adam Green

Published:

Published 1/23/2022

Tags: