I am trying to get HMR working with my SvelteKit project using Docker and Docker Compose, but i just cant figure it out. I have been looking up several sources, and all look very similar, but have each their slight differences. My main source of inspiration is this Youtube video.
As of now, i can get my project to run, but when i change files, the container is not being updated. My database works well, it runs and i get access to it in the container when my application is developed by the simple "npm run dev". i have not yet tried to access the database when both database and application is containerized.
./application/Dockerfile
:
FROM node:21-alpine
WORKDIR /usr/src/app
COPY package.json ./
COPY package-lock.json ./
RUN npm install && npm cache clean --force
COPY . .
EXPOSE 5173
CMD ["npm", "run", "host"]
./application/vite.config.ts
:
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
});
./docker-compose.yaml
:
version: '3.8'
services:
surrealdb:
image: surrealdb/surrealdb:latest
env_file:
- .env
entrypoint:
- /surreal
- start
- --user
- $DATABASE_USER
- --pass
- $DATABASE_PASS
- file:data
volumes:
- $DATABASE_LOCATION:/data
ports:
- $DATABASE_PORT:8000
extra_hosts:
- "host.docker.internal:host-gateway"
sveltekit:
env_file:
- .env
build:
context: ./application
ports:
- 5173:5173
volumes:
- ./application:/usr/src/app
- /usr/src/app/node_modules/
./.env
:
# Raspberry PI IP Address.
IP_ADDRESS=192.168.1.20
DATABASE_PORT=3456
# Wifi credentials.
WIFI_SSID=my-ssid
WIFI_PASSWORD=my-password
# Database credentials.
DATABASE_USER=admin_username
DATABASE_PASS=some_secret_password
# Database location on disk.
DATABASE_LOCATION=./database/data
# Database namespace and database.
SURREAL_NS=root
SURREAL_DB=root
# Others
# SURREAL_PATH=file:data
SURREAL_CAPS_ALLOW_SCRIPT=true
SURREAL_AUTH=true
How do i get HMR working from this standpoint?
This is how I got HMR to work in a dockerized SvelteKit app running in dev mode (the following assumes the docker configuration files are located at the root of your SvelteKit project, amend paths if otherwise):
# ./Dockerfile
# Use the alpine version that suits your needs, based
# on the Node version you want to use. If possible use
# the latest stable version (recommended for a newly
# created SvelteKit project).
FROM node:alpine
# Use whichever container directory you want as long
# as you make sure to use it consistently in further
# configuration. I'll just use '/app' here for simplicity.
WORKDIR '/app'
COPY package.json .
RUN npm install
COPY . .
# Using the --host 0.0.0.0 option (which is passed to Vite)
# was the only way I could get the dev/HMR mode to be
# accessible from outside the container.
CMD npm run dev -- --host 0.0.0.0
Build and test with:
docker build -t docker-svelte-test:latest .
docker run -it -p 5173:5173 -v /app/node_modules -v .:/app docker-svelte-test:latest
The -it
flag will let you interact with the server (restart, quit, etc.). The port mapping option is self-explanatory (note that I did not need to EXPOSE
the port in the Dockerfile). The volume (-v
) declarations are very important to get HMR to work, and need to be declared in that order. The first one persists /app/node_modules
, which allows us to then map /app
to our project's root directory without impacting node_modules
. Because /app
is mapped to the project's directory, changes made to the source files will be immediately reflected in the application running on the container (= HMR working).
Once you have tested that HMR is indeed working, putting together a corresponding docker-compose
file is very straightforward:
# ./docker-compose.yml
services:
dev:
build:
context: .
ports:
- 5173:5173
volumes:
- /app/node_modules
- .:/app
And you can invoke it with docker compose up
. Note that you no longer have the benefit of an interactive server (the -it
flag we passed to docker run
is no longer available). HMR should still be fully functional however.
Note that this is only valid as long as you do not install new modules with npm
. If you do, you will have to rebuild your image and restart your container. But for HTML/CSS editing using HMR it works perfectly.
I have tested this using adpater-auto
as well as adapter-static
. In fact it should work with any adapters as these only come into play during the build phase and are thus irrelevant in the context of getting HMR to work in dev mode.