Skip to content

Update Docker and pnpm fetch to be more aligned and link to each other #569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions docs/cli/fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,28 @@ This command is specifically designed to improve building a docker image.
You may have read the [official guide] to writing a Dockerfile for a Node.js
app, if you haven't read it yet, you may want to read it first.

Also see [Working wirh Docker](../docker.md), for examples of multi-stage
builds, and `pnpm deploy` that can be combined with this command for a smaller
final image.

From that guide, we learn to write an optimized Dockerfile for projects using
pnpm, which looks like

```Dockerfile
FROM node:20
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable pnpm && corepack install -g pnpm@latest-10

WORKDIR /path/to/somewhere

RUN corepack enable pnpm && corepack install -g pnpm@latest-10

# Files required by pnpm install
COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml .pnpmfile.cjs ./

# If you patched any package, include patches before install too
COPY patches patches

RUN pnpm install --frozen-lockfile --prod
RUN pnpm --mount=type=cache,id=pnpm,target=/pnpm/store install --frozen-lockfile --prod

# Bundle app source
COPY . .
Expand All @@ -52,11 +57,12 @@ look like

```Dockerfile
FROM node:20
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable pnpm && corepack install -g pnpm@latest-10

WORKDIR /path/to/somewhere

RUN corepack enable pnpm && corepack install -g pnpm@latest-10

# Files required by pnpm install
COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml .pnpmfile.cjs ./

Expand All @@ -69,7 +75,7 @@ COPY patches patches
COPY packages/foo/package.json packages/foo/
COPY packages/bar/package.json packages/bar/

RUN pnpm install --frozen-lockfile --prod
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --prod

# Bundle app source
COPY . .
Expand All @@ -86,18 +92,19 @@ to load packages into the virtual store using only information from a lockfile a

```Dockerfile
FROM node:20
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable pnpm && corepack install -g pnpm@latest-10

WORKDIR /path/to/somewhere

RUN corepack enable pnpm && corepack install -g pnpm@latest-10

# pnpm fetch does require only lockfile
COPY pnpm-lock.yaml pnpm-workspace.yaml ./

# If you patched any package, include patches before running pnpm fetch
COPY patches patches

RUN pnpm fetch --prod
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm fetch --prod


ADD . ./
Expand Down
53 changes: 53 additions & 0 deletions docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ id: docker
title: Working with Docker
---

Also see [pnpm fetch](./cli/fetch.md) for a command that can be used to speed up consecutive builds.

:::note

It is impossible to create reflinks or hardlinks between a Docker container and the host filesystem during build time.
Expand Down Expand Up @@ -165,3 +167,54 @@ COPY --from=prod /app/dist /app/dist
EXPOSE 8000
CMD [ "pnpm", "start" ]
```

### Example 4: All techniques in one

A verstaile option is to just use both fetch, deploy, cache mounts, newer Docker
features like `--link` all in one Docker file, and benefit from the build
performance and image size reducation at the cost of a more complex Dockerfile.

This also includes running as a normal user instead of root, and properly
caching pnpm with corepack so the image won't need to download it on startup.

```dockerfile title="Dockerfile"
# syntax=docker/dockerfile:1
FROM node:22 AS build
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV COREPACK_HOME="/corepack"
# Package to be built and deployed from the workspace
ARG PACKAGE=example

WORKDIR /workspace
# The package.json is for corepack, pnpm fetch needs only the lockfile and workspace configuration
COPY --link package.json pnpm-lock.yaml pnpm-workspace.yaml ./
# If you have patches:
# COPY --link patches patches
RUN corepack enable && corepack install
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm fetch

COPY --link . .

RUN pnpm install --offline --frozen-lockfile

RUN pnpm --filter $PACKAGE... build

RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm --filter $PACKAGE deploy --prod deploy

FROM node:22-slim AS runtime
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV COREPACK_HOME="/corepack"

WORKDIR /app
COPY --link --from=build /workspace/deploy .

RUN corepack enable && corepack install
ENV COREPACK_DEFAULT_TO_LATEST=0 COREPACK_ENABLE_NETWORK=0

USER 1000
CMD ["pnpm", "--silent", "start"]
```