Svelte in a Container
Learning objectives
- You know how to run Svelte in a container.
Building on top of the work in the chapter on Application Containerization, let's add Svelte to our project. We start from the situation where we were at the end of the part Database Migrations.
tree --dirsfirst
.
├── api
│ ├── app.js
│ ├── app-run.js
│ ├── deps.js
│ └── Dockerfile
├── flyway
│ └── sql
│ ├── V1__todos.sql
│ ├── V2__users.sql
│ ├── V3__addresses.sql
│ └── V4__books_and_ratings.sql
├── docker-compose.yml
└── project.env
3 directories, 10 files
Creating a new Svelte project
In the same folder with docker-compose.yml
, run the Svelte wizard used for creating a new project. Use ui
as the name of the project. Select the Skeleton project
as the template, do not add TypeScript, and select Svelte 5 preview from the additional options. When the wizard is ready, the folder structure of the project should similar to the following.
tree --dirsfirst
.
├── api
│ ├── app.js
│ ├── app-run.js
│ ├── deps.js
│ └── Dockerfile
├── flyway
│ └── sql
│ ├── V1__todos.sql
│ ├── V2__users.sql
│ ├── V3__addresses.sql
│ └── V4__user_specific_todos.sql
├── ui
│ ├── src
│ │ ├── lib
│ │ │ └── index.js
│ │ ├── routes
│ │ │ └── +page.svelte
│ │ └── app.html
│ ├── static
│ │ └── favicon.png
│ ├── package.json
│ ├── README.md
│ ├── svelte.config.js
│ └── vite.config.js
├── docker-compose.yml
└── project.env
Go to the ui
folder on command line and run the command npm install
to install the dependencies. Check out the currently used package.json
content from the Svelte and npm page.
Vite and Docker
Svelte uses vite in the background for running the application. Vite is a development server that can be used for running the application in development mode. Vite is also used for building the application for production.
When we run applications in Docker, they are run within a containerized environment with specific networking options. To provide information to Vite that the application is run in a containerized environment, we need to modify the vite.config.js
to indicate to Vite that the server should act as a host -- this way, the application is accessible from the host machine.
Modify the vite.config.js
to match the following.
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [sveltekit()],
server: {
host: true,
},
});
Adding a Dockerfile
Create a Dockerfile
to the folder ui
. In the Dockerfile, we'll load the Node.js image and copy the package- and config-related files to the image. After this, we'll install the dependencies, and copy the rest of the files to the image. This is similar to what we do with Deno images -- we essentially first cache the dependencies and then copy the remaining contents to the project.
Once the rest of the files are copied to the image, we expose the port 5173
, define a HOST
variable to the environment, and define the command that is used to run the image. Here, we use the command npm run dev -- --host 0.0.0.0
. With these, we essentially seek to enforce that the application is run so that it can be accessed from outside the container.
As a whole, the Dockerfile (in the folder ui
) should be as follows.
FROM node:21-alpine
WORKDIR /app
COPY package*.json .
COPY *config.js .
RUN npm install
COPY . .
EXPOSE 5173
ENV HOST=0.0.0.0
CMD [ "npm", "run", "dev", "--", "--host", "0.0.0.0"]
Adding the service
Let's next add the service to the docker-compose.yml
file. Let's call the service ui
. The service is built from the folder ui
of the project (i.e., the folder that has the Svelte application). For development purposes, we bind the folder ui
of our project to the /app
folder of the container -- this way, changes to the project are immediately reflected in the container. We also expose the port 5173
of the container to the port 5173
of the host machine, and finally define that the ui
depends on the service api
.
This configuration looks as follows.
ui:
build: ui
restart: unless-stopped
volumes:
- ./ui:/app
ports:
- 5173:5173
depends_on:
- api
With the above, the docker-compose.yml
is now as follows.
services:
api:
build: api
restart: unless-stopped
volumes:
- ./api:/app
ports:
- 8000:8000
depends_on:
- database
env_file:
- project.env
database:
container_name: postgresql_database
image: postgres:16.1
restart: unless-stopped
env_file:
- project.env
database-migrations:
image: flyway/flyway:10.0.0-alpine
env_file:
- project.env
depends_on:
- database
volumes:
- ./flyway/sql:/flyway/sql
command: -connectRetries=60 -baselineOnMigrate=true migrate
ui:
build: ui
restart: unless-stopped
volumes:
- ./ui:/app
ports:
- 5173:5173
depends_on:
- api
Running the project
Now, in the root folder of the project, we can run the project using the docker compose up --build
command. This builds the images and starts the containers.
docker compose up --build
..
Now, the Deno backend is available at the address http://localhost:8000
and the Svelte frontend is available at the address http://localhost:5173
.