Search code examples
dockersveltekitpnpm

in Dockerfile, how to copy node_modules installed by pnpm?


In PNPM repositories, node_modules have many hard links(not symbolic links) of packages to the local .pnpm store.

Now I need to make a Dockerfile with a multi-stage building process for my SveltKit repo,

and I am stuck with copying node_modules folder from my builder to my deployer docker image below:

FROM node:18.16.0-alpine AS builder
RUN npm install -g pnpm
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
RUN pnpm prune --prod

FROM node:18.16.0-alpine AS deployer
WORKDIR /app
COPY --from=builder /app/build build/
COPY --from=builder /app/node_modules ./node_modules
COPY package.json .
EXPOSE 5173
CMD [ "node", "build" ]

Because PNPM is not like NPM. Direct copying the node_modules folder will not work.

I have tried to convert the pnpm-lock.yaml into package-lock.json by npm i --package-lock-only, but it took a very long time then failed with this error message: Cannot set properties of null (setting 'dev').

What is the proper solution or workaround?


Solution

  • I was thinking about use Linux cp -rL command to deal with hard links/symbolic links:

    RUN cp -rL node_modules node_modules2
    RUN rm -r node_modules
    RUN mv node_modules2 node_modules
    

    But that is not an efficient way to solve it.

    Thanks for @DavidMaze. PNPM does use hard links and it seems to work fine with Docker COPY command. Here is a very contrived Dockerfile I tried and it works!

    FROM node:18.16.0-alpine AS base
    RUN npm install -g pnpm
    WORKDIR /app
    COPY package.json pnpm-lock.yaml ./
    RUN pnpm install --frozen-lockfile
    
    FROM node:18.16.0-alpine
    WORKDIR /app
    COPY . .
    COPY --from=base /app/node_modules ./node_modules
    EXPOSE 5173
    CMD [ "npm", "run", "dev" ]
    

    As the above Dockerfile is not a proper way to build a SvelteKit image, you have to comment out those below in your .dockerignore:

    #.svelte-kit
    #**/.env
    

    To build the image:

    docker build . -t project1:v2
    docker run -p5173:5173 -p 24678:24678 project1:v2