Lucdev Website
SvelteKit illustration

Create an SPA with SvelteKit including Docker

Apr 12, 2024 - 5 minutes 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, 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

Shell
npm create svelte@latest 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.

Console Output
┌  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.

Shell
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

Shell
touch src/routes/+layout.ts

Add the following contents:

src/routes/+layout.ts
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.

Shell
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:

svelte.config.js
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.

Shell
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

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

Shell
touch .dockerignore

Add the following contents:

.dockerignore
.git
.gitignore
dist
build
Dockerfile*
node_modules
*.md
.env*
.svelte*

Create a file called Dockerfile

Shell
touch Dockerfile

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

Dockerfile
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:

Shell
docker build -t my-app .

Run the container with the following command:

Shell
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!

Tags: