🧑💻 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.
over the weekend we added an oft-requested feature to the SvelteKit beta: SPA mode, aka 'no SSR, please' : https://t.co/vWocTyNYsa
— Rich Harris (@Rich_Harris) March 29, 2021
(there's one final step we need to take before you can use it everywhere — thoughts welcome https://t.co/IgtWQ3Wfnl)
but there's more! 1/2 pic.twitter.com/ob4TPhhoiH
not an SPA fan either but it was a dealbreaker for a lot of folks. the alternative to supporting it is that people will invent their own solutions, most likely with other flaws
— Rich Harris (@Rich_Harris) March 29, 2021
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
npm create svelte@latest my-app
pnpm create svelte@latest my-app
npm create svelte@latest my-app
npm create svelte@latest my-app
pnpm 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.
┌ 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
pnpm i
npm i
npm i
pnpm 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
pnpm remove @sveltejs/adapter-auto
pnpm add -D @sveltejs/adapter-static
npm remove @sveltejs/adapter-auto
npm i -D @sveltejs/adapter-static
npm remove @sveltejs/adapter-auto
npm i -D @sveltejs/adapter-static
pnpm remove @sveltejs/adapter-auto
pnpm add -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
pnpm run dev
npm run dev
npm run dev
pnpm 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
dist
build
Dockerfile*
node_modules
*.md
.env*
.svelte*
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
FROM node:lts AS builder
WORKDIR /app
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@latest-9 --activate
COPY . .
RUN pnpm install
RUN pnpm run build
FROM nginx:latest as runner
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
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
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
FROM node:lts AS builder
WORKDIR /app
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@latest-9 --activate
COPY . .
RUN pnpm install
RUN pnpm 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!