skip to Main Content

With the help from SO community I was finally able to dockerize my Sveltekit app and access it from the browser (this was an issue initially). So far so good, but now every time I perform a code change I need to re-build and redeploy my container which obviously is not acceptable. Hot reload is not working, I’ve been trying multiple things I’ve found online but none of them have worked so far.

Here’s my Dockerfile:

FROM node:19-alpine

# Set the Node environment to development to ensure all packages are installed
ENV NODE_ENV development

# Change our current working directory
WORKDIR /app

# Copy over `package.json` and lock files to optimize the build process
COPY  package.json package-lock.json ./
# Install Node modules
RUN npm install

# Copy over rest of the project files
COPY . .

# Perhaps we need to build it for production, but apparently is not needed to run dev script.
# RUN npm run build

# Expose port 3000 for the SvelteKit app and 24678 for Vite's HMR
EXPOSE 3333
EXPOSE 8080
EXPOSE 24678

CMD ["npm", "run", "dev"]

My docker-compose:

version: "3.9"

services:
  dmc-web:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: dmc-web
    restart: always
    ports:
      - "3000:3000"
      - "3010:3010"
      - "8080:8080"
      - "5050:5050"
      - "24678:24678"
    volumes:
      - ./:/var/www/html

the scripts from my package.json:

    "scripts": {
        "dev": "vite dev --host 0.0.0.0",
        "build": "vite build",
        "preview": "vite preview",
        "test": "playwright test",
        "lint": "prettier --check . && eslint .",
        "format": "prettier --write ."
    },

and my vite.config.js:

import { sveltekit } from '@sveltejs/kit/vite';
import {defineConfig} from "vite";

export default defineConfig({
    plugins: [sveltekit()],
    server: {
        watch: {
            usePolling: true,
        },
        host: true, // needed for the DC port mapping to work
        strictPort: true,
        port: 8080,
    }
});

any idea what am I missing? I can reach my app at http://localhost:8080 but cannot get to reload the app when a code change happens.

Thanks.

2

Answers


  1. Why are you using docker for local development? Check this https://stackoverflow.com/a/70159286/3957754

    Nodejs works very well even on windows, so my advice is to develop directly in the host with a simple nodejs installation. Your hot reload should work.

    Docker is for your test, staging or production servers in which you don’t want a hot-reload because reals users are using your web. Hot reload is only for local development.

    container process

    When the docker starts, is linked to a live and foreground process. If this process ends or is restarted, the entire container will crash. Check this https://stackoverflow.com/a/68593731/3957754

    That’s why docker goal is not related to hot-reload at source code level

    anyway

    Anyway, if you have a machine in which to have the workspace (nodejs, git, etc) is so complex, you could use docker with nodejs hot reload following these steps:

    • Don’t use Dockerfile, use directly docker run ubuntu …. You are working with nodejs not with c#, php or similar follies
    • At the root of your workspace (package.json) execute this
    docker run -p 8080:8080 -v $(pwd):/src node:19-alpine bash
    
    • The previous sentence will create a container not linked to a tcp process. So you will have new sub-shell, with nodejs 19 and alpine ready to use
    • Execute the classic
    cd /src
    npm install
    npm run dev
    
    • If your app works fine, the hot reload should work. If don’t work, try without docker and share us the result
    Login or Signup to reply.
  2. Solution

    The workspace in question does not work simply because it does not bind-mount the source directory. Other than that, it has no problem whatsoever.

    Here’s working code at my github:
    https://github.com/rabelais88/stackoverflow-answers/tree/main/74680419-svelte-docker-HMR

    1. Proper bind mount in docker-compose

    The docker-compose.yaml from the question only mounts the result of previous build, not the current source files.

    # 🚨wrong
        volumes:
          - ./:/var/www/html
    # ✅answer
        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:/home/node/app/src
          - ./static:/home/node/app/static
          - ./vite.config.js:/home/node/app/vite.config.js
          - ./tsconfig.json:/home/node/app/tsconfig.json
          - ./svelte.config.js:/home/node/app/svelte.config.js
    

    2. dockerfile should not include file copy and command

    dockerfile does not always have to include command. it is necessary when 1)the result has to be preserved 2)the process lifecycle is critical to image. In this case 1)the result is not quite certain because the source may not be complete at the moment of booting, 2) the process lifecycle is not really important because the user may manually execute or close the container. The local development environment for VSCode + Docker, a.k.a VSCode devcontainer, also uses sleep infinity command for this reason.

    As mentioned above, the code cannot be copied to docker space because it would conflict with bind-mounted files. To avoid both files collide, just remove COPY and CMD command from dockerfile and add more commands at docker-compose.yaml

    # dockerfile
    
    # 🚨wrong
    COPY  package.json package-lock.json ./
    RUN npm install
    COPY . .
    # ...
    CMD ["npm", "run", "dev"]
    
    # ✅answer
    COPY  package*.json ./
    RUN npm install
    # comment out COPY and CMD
    # COPY . .
    # ...
    # CMD ["npm", "run", "dev"]
    

    and add command to docker-compose

    # docker-compose.yaml
    services:
      svelte:
        # ...
        command: npm dev
    

    and rest of configs in the question are not necessary. you can check this out from my working demo at Github

    Edit

    I just did this, but when running it I’m getting Error: Cannot find module ‘/app/npm dev’.

    the answer uses arbitrary settings. the volumes and CMD may has to be changed accordingly.

    i.e.)

    # docker-compose.yaml
    volumes:
      - ./src:/$YOUR_APP_DIR/src
      - ./static:/$YOUR_APP_DIR/static
      # ...
    

    I’ve used /home/node/app as WORKDIR because /home/node is used as main WORKDIR for official node docker image. However, it is not necessary to use the same folder. If you’re going to use /home/node/app, make sure create the folder before use.

    RUN mkdir -p /home/node/app
    WORKDIR /home/node/app
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search