Context
I have two dockerized apps, one contains the frontend (Sveltekit) and one contains the backend API (Laravel). Both apps are on their own directory and contain separate docker-compose files. There's a docker-compose for the frontend app and a docker-compose for the backend API app. So far, while testing I simply run my frontend app locally (not in a container) and was able to fetch data from the API which was running on a container.
Problem
The problem I encountered first was when I tried to use the dockerized version of the frontend app. The container built correctly and the UI loaded but it can't fetch data from the API since the API lives in a different container. Remember, both apps have their own docker-compose file so for each app I run docker-compose up --build. It makes sense that I cannot access the backend API from the frontend container, after all I guess they are in different networks.
So I tried to get rid of the docker-compose file in my frontend project and simply create a service in the docker-compose that belongs to the backend to load the frontend by referencing the existing Dockerfile that belongs to the frontend project. When running:
docker-compose up --build
the build seems to be successful (no errors) but now I cannot access the frontend via the URL.
What's going on?
Here's the frontend's Dockerfile:
# Dockerfile
# base stage
FROM node:21-alpine AS base
WORKDIR /app
# copy everything
COPY . .
# install dependencies
RUN npm install
# ----------------------------------------------------------
FROM base AS dev
# Set the Node environment to development to ensure all packages are installed
ENV NODE_ENV development
EXPOSE 5137
CMD ["npm", "run", "dev"]
# ----------------------------------------------------------
FROM base AS build
# build the app
RUN npm run build
# run stage, to separate it from the build stage, to save disk storage
FROM node:21-alpine AS prod
WORKDIR /app
# Set the Node environment to development to ensure all packages are installed
ENV NODE_ENV production
# copy stuff from the build stage
COPY --from=build /app/package*.json ./
COPY --from=build /app/build ./build
# expose the app's port
EXPOSE 3000
# run the server
CMD ["node", "./build/index.js"]
And here's the docker-compose file:
version: "3.9"
services:
app:
build:
context: ./
dockerfile: Dockerfile
image: dmc
container_name: dmc-app
restart: unless-stopped
working_dir: /var/www/
depends_on:
- db
- nginx
volumes:
- ./:/var/www/
- ./docker/php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
- ./docker/php/conf.d/error_reporting.ini:/usr/local/etc/php/conf.d/error_reporting.ini
- ./images:/public/images
expose:
- "9003"
networks:
- dmc-net
nginx:
image: nginx:1.23.2-alpine
container_name: dmc-nginx
restart: unless-stopped
ports:
- "8000:80"
volumes:
- ./:/var/www
- ./docker-compose/nginx:/etc/nginx/conf.d
networks:
- dmc-net
supervisor:
image: dmc
container_name: dmc-supervisor
networks:
- dmc-net
depends_on:
- app
- nginx
command:
- supervisord
db:
image: mysql:8.0.31
container_name: dmc-db
restart: unless-stopped
# using 3307 on the host machine to avoid collisions in case there's a local MySQL instance installed already.
ports:
- "3307:3306"
# use the variables declared in .env file
environment:
MYSQL_HOST: ${DB_HOST}
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: abcd1234
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
- mysql-data:/var/lib/mysql
networks:
- dmc-net
dmc-web:
build:
context: .
dockerfile: /Users/hansgruber/Desktop/webdev/projects/dundermifflin-ui/Dockerfile
target: dev
container_name: dmc-web
restart: always
ports:
- "5173:5173"
volumes:
# it avoids mounting the workspace root
# because it may cause OS specific node_modules folder
# or build folder(.svelte-kit) to be mounted.
# they conflict with the temporary results from docker space.
# this is why many mono repos utilize ./src folder
- ./src:/app/src
- ./static:/app/app/static
- ./static:/app/static/
depends_on:
- app
- nginx
- db
networks:
- dmc-net
networks:
dmc-net:
driver: bridge
volumes:
mysql-data:
I don't see any port collision and the service also uses the same network.
Any idea what's wrong?
Initially I thought it was perhaps a CORS issue or something like that, but I'd expect to see any output in the console when attempting to access http://localhost:5173/ which is the URL displayed in the build output:
dmc-web |
dmc-web | > dev
dmc-web | > vite
dmc-web |
dmc-web |
dmc-web | VITE v3.2.1 ready in 403 ms
dmc-web |
dmc-web | ➜ Local: http://localhost:5173/
dmc-web | ➜ Network: use --host to expose
dmc-web |
dmc-web | LARAVEL v9.40.1 plugin v0.5.4
dmc-web |
dmc-web | ➜ APP_URL: http://localhost
UPDATE
So I was able to partially make it work. Here's what I did differently:
- My frontend project lives in a separate location, it is not located at the same location where the backend project resides. In
docker-composeI was usingcontext: .but it should have beencontext: /Users/hansgruber/Desktop/webdev/projects/dundermifflin-uiwhich is actually pointing to the folder where the project resides. I have updated this in mydocker-compose.
Now, if I tried to build it using target: dev for the frontend project (dmc-web) then I still cannot access the UI, BUT if I run it using target: dev then the UI loads. It's not fetching anything from the backend, meaning that it's not connecting to it and that's something I'm looking into.
Now the issue is that the build using target: dev is failing.
Any suggestions?
UPDATE 2
I've updated vite.config.js and added a server property. Tried different ports and for each port I built the app again. The ports used were 3000, 5137 and 5173. Here's the file contents:
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [sveltekit()],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
},
server: {
host: '0.0.0.0',
port: 5137, // tested 5137, 3000, 5173
}
});
When using 3000 and 5173 I'm getting:
dmc-web | src/app.html does not exist
which seems like it is establishing a connection but it's not finding the files.
When using 5137 I'm getting:
This site can’t be reached. localhost refused to connect.
Meaning that it cannot establish connection at all.
localhost:8080? Then access them the same aslocalhost:8080or whatever port you used unless there are ports missing or conflictinghttp://localhost:8000/api/. The issue is the frontend, I mean, at the moment is not even that the frontend is cannot fetch data from the backend, the problem is that the frontend is not loading at all. Some UI should load but fail to fetch data, but that's not happening