SvelteKit illustration

Create an SPA with SvelteKit including Docker

ยท5 min read

๐Ÿง‘โ€๐Ÿ’ป This article assumes you have intermediate experience with the command line.

Recently, I been working on a side-project, and I decided to build a single page application for it's UI. So I wanted to share this information with y'all.

Previously, you would use something like svelte-navigator or svelte-spa-router, In fact, you can still use this tools today!

However, Sveltekit exists for a reason, and that is to have an opinionated way for building web applications with Svelte.

As Rich Harris said ( here & here ), the Svelte framework creator, other solutions might have their flaws.

I won't list the reasons why server-side rendering is better or when should you build an SPA instead. Every choice has it's pros and cons.

Getting started

Let's create a new project

npx sv create my-app

The program will make you some questions, I will choosing the option that says "SvelteKit demo app", and I will choose to use TypeScript.

I will skip any of the aditional options.

โ”Œ  Welcome to SvelteKit!
โ”‚
โ—‡  Which Svelte app template?
โ”‚  SvelteKit demo app
โ”‚
โ—‡  Add type checking with TypeScript?
โ”‚  Yes, using TypeScript syntax
โ”‚
โ—‡  Select additional options (use arrow keys/space bar)
โ”‚  none
โ”‚
โ””  Your project is ready!

Open your favorite code editor with that folder. I will be using VS Code.

Don't forget to install the packages.

npm i

How to enable SPA mode

You can also consult the official documentation in this link

Lets create the following file src/routes/+layout.ts

touch src/routes/+layout.ts

Add the following contents:

export const ssr = false;

โš  Do not confuse this file with +layout.svelte they're different files, and only in the .ts this will work.

Now we have to switch the adapter, to use the static one.

npm remove @sveltejs/adapter-auto
npm i -D @sveltejs/adapter-static

Open the file that contains the svelte config svelte.config.js

Replace the adapter to use the static one, here is how it should look like:

import adapter from '@sveltejs/adapter-static';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
 
/** @type {import('@sveltejs/kit').Config} */
const config = {
  // Consult https://kit.svelte.dev/docs/integrations#preprocessors
  // for more information about preprocessors
  preprocess: vitePreprocess(),
 
  kit: {
    adapter: adapter({
      fallback: 'index.html', // may differ from host to host
    }),
  },
};
 
export default config;

This should be enough to turn it into an SPA.

You can run the application if you want to play around with it.

npm run dev

How to dockerize any Single-page-application

TL;DR: Run any http server that allows rewrites and redirect everything to "index.html".

Let's do that! For that, I will using nginx.

โœ Create a file called nginx.conf

events {}

http {
    default_type application/octet-stream;
    include /etc/nginx/mime.types;

    server {
        listen 3000;
        root /usr/share/nginx/html;


        gzip on;
        gzip_types text/html application/javascript application/json text/css;

        location / {
            try_files $uri $uri/ $uri.html /index.html;
        }

        location ~* \.(?:css|js|svg|jpg|png|webp|mp4|m4a|webm|ogg|opus)$ {
            expires 30d;
            add_header Cache-Control "public";
        }

        location ~* \.(?:json)$ {
            expires 1d;
            add_header Cache-Control "public";
        }
    }
}

You can tune in this config if you want to, here you can see that it gives a long time cache for any static request.

Create a file called .dockerignore

touch .dockerignore

Add the following contents:

.git
.gitignore
.svelte-kit
dist
build
Dockerfile*
node_modules
*.md
.env*

Create a file called Dockerfile

touch Dockerfile

As expected, the contents vary depending on the package manager you are using.

FROM node:lts AS builder
WORKDIR /app
 
COPY . .
 
RUN npm ci
RUN npm run build
 
FROM nginx:latest as runner
 
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
 

Let's build the docker image:

docker build -t my-app .

Run the container with the following command:

docker run -p 3000:3000 -t my-app

This will forward the port "3000" from the container to match :3000 on your local computer.

๐Ÿง  Learn more about docker run

That should be all!

๐Ÿ‘‹ Happy coding!

Updated: Thank you! anurag for poiting out the incorrect Dockerignore entry.