0

I have a basic NodeJS webpage set up in Docker. It works fine, except for when I add an npm dependency. The initial setup works just fine, but when I have built the container once, and then want to add a dependency using npm install, it installs fine, but it simply doesn't show up in my container.

Looking around, it seems like the issue is that the mounted volume is overwriting the data that npm install created.

So, the question: Is it possible to use a mounted volume, like .LogServer:/app without overwriting the node_modules folder each time the container is built?

Here's my docker-compose.yaml:

    Log-Server:    
        container_name: Log-Server
        image: node/logserver
        build:
            context: ./LogServer
        restart: unless-stopped    
        ports: 
            - "3004:3000" # Webpage
            - "3005:3005" # Websocket
        environment: 
            PORT: 3000
        volumes:
            - logserver_node_modules:/app/node_modules/
            - ./LogServer:/app
            - ./Node-RED/data/logs:/logs/Node-RED/:ro
        networks:
            - docker-lan
        # command: npm start
        command: npm test

Dockerfile:

FROM node:17-alpine3.15

WORKDIR /app

COPY package*.json ./

RUN npm ci

Edit after question was closed.

If you look at the linked question, the answers provided there are things I have already implemented, specifically this approach, because I want the npm modules to be persistent. Obviously, linking something that I am already doing will not answer my question.

Maybe my issue wasn't described clearly enough. I indeed want the node_modules folder to be persistent in my container, but non-existent on my development machine. That's achieved by the line logserver_node_modules:/app/node_modules/. That's not the issue I'm having, that works fine. The issue I'm having is that newly added dependencies don't show up in the container. I'm pretty sure this is due to the mounted volume overwriting what is installed from the Dockerfile.

Simply put:

  • Dockerfile correctly installs all dependencies into /app/node_modules/
  • docker-compose mounts logserver_node_modules on /app/node_modules/, overwriting what was put there by the Dockerfile.

This is confirmed by the fact that changing the package.json file prevents docker-compose up from using cache on the last two steps (copying package*.json and npm install).

So the real question is: How can I have a persistent node_modules volume, yet also be able to easily update my dependencies if required?

As a workaround I changed my package.json file's test command to

"scripts": {
    "test": "npm i && nodemon server.js",
    "start": "node server.js"
  },

This works just fine, and I think it's only a bit slower when nothing has changed, but it seems like a hack. Any other, better solutions would be nice, if they exist.

Timmiej93
  • 1,328
  • 1
  • 16
  • 35
  • Docker can't do this without the anonymous `node_modules` volume hack. I'd recommend `COPY`ing the application source into the image and deleting the `volumes:` entirely; since the image has an isolated copy of the tree it won't interfere with the `node_modules` directory in your host non-Docker development environment. – David Maze Feb 09 '22 at 14:51
  • (One of the problems with the `node_modules` anonymous volume is that the contents of the volume hide what's in the image; or, put another way, it tells Docker to ignore any changes to the `package.json` file. You need to delete the volume in some way. If you build the whole thing into the image then `docker build` will rebuild it normally.) – David Maze Feb 09 '22 at 14:52
  • @DavidMaze That won't work for development. Currently, simply saving the server file reloads the server. Rebuilding the entire container every time I make a tiny change is not going to work, of course. If this was a production container, that would indeed be the obvious choice, but in a production container I wouldn't need to change dependencies either. – Timmiej93 Feb 09 '22 at 18:22
  • @DavidMaze I don't think that's true. As I understand it, docker installs the newly added modules into `/app/node_modules/` just fine, but after it has done that, docker-compose writes the contents of `logserver_node_modules` to the container volume `/app/node_modules/`, overwriting what the Dockerfile just installed through npm. This is pretty much confirmed by the fact that changing `packages.json` makes `docker-compose up` not use cache for the last two steps, meaning it does see the changes, and is installing new packages, they just get overwritten later. – Timmiej93 Feb 09 '22 at 18:39
  • It sounds like you have two conflicting requests. You want node_modules to be persistent, but you also want them to be replaced by what is in the image? You'll need to pick one or the other. – BMitch Feb 10 '22 at 14:45
  • @BMitch That's what's happening, but it's not my request. My goal has 2 criteria: `node_modules` has to be persistent, and I have to be able to install new dependencies. I don't care how it works (so as you say, using the Dockerfile probably isn't going to work), as long as it works, and isn't purely a hack. The example at the bottom of my posts shows my hacky workaround, but I feel like there has to be a better way. – Timmiej93 Feb 10 '22 at 18:14

0 Answers0