Replies: 15 comments 1 reply
-
I think there are many things need to considered, e.g. lifecycle script, and maybe monorepo will also be affected. |
Beta Was this translation helpful? Give feedback.
-
Well, w/o a |
Beta Was this translation helpful? Give feedback.
-
It may be possible to create a new command ADD pnpm-lock.yaml ./
RUN pnpm install --ci --only-from-lockfile # Proposed option for this feature
ADD . ./ # package.json will be included
RUN pnpm postinstall # Verify the lockfile and run scripts
|
Beta Was this translation helpful? Give feedback.
-
I am not sure what advantage this gives you then. |
Beta Was this translation helpful? Give feedback.
-
To boost the Docker build process. ADD package.json package-lock.json ./
# npm ci will also be cached if package.json package-lock.json is not modified
RUN npm ci
ADD . ./ instead of the naive way # Add all the things of the project. If any files of your project, the digest of above
# layer is changed and all following steps can not be cached any more
ADD . ./
# You will reinstall all packages even if you just changed a bit of your code
RUN npm ci While even using the suggested pattern, anyone modify the package.json for just adding a script or just bump the version will also make cache invalided. Since installing pacakges is the step consumes most of the time, it's worth to seperate installing packages as a single step to be cache friendly. |
Beta Was this translation helpful? Give feedback.
-
Actually this feature will made monorepo be easily build by docker. Currently, it's very hard to write and maintains a Dockerfile for monorepo using the pattern described before. |
Beta Was this translation helpful? Give feedback.
-
Currently, our first docker layer for all builds within our monorepo is the pnpm install layer, which requires copying both the lockfile and all package.json files in the repo. If a script on one of those packages changes, or even some other arbitrary metadata, but dependencies are left untouched, the entire build cache is invalidated. I've toyed with switching from a shared lockfile to individual package locks for better control over cache-invalidation, but the initial development install performance is 5-10x slower, which could result in moving the problem from our CI pipelines to local developer machines. I've also looked into running a filtered install based on the specific application that is being built, but For each approach I've looked into, I keep coming back to this topic. If we were able to install dependencies from the lockfile only, the problem is largely mitigated, resulting in hours of weekly CI congestion being removed. Running |
Beta Was this translation helpful? Give feedback.
-
I think there are too many edge cases. Like the bin field for instance. I don't think duplicating a lot of fields in the lockfile is a good idea. Maybe we could create a new manifest file. Something like |
Beta Was this translation helpful? Give feedback.
-
#1670 could be another way to boost the docker build process. If we were able to save all required package to local store at the first time, the install can be done offline. COPY pnpm-lock.yaml ./
RUN pnpm store add-from-lock-file pnpm-lock.yaml # Proposed command for #1670
COPY . .
RUN pnpm install --prefer-offline As long as the lockfile is not changed, the cache will be still valid and the actual install process can be done without network I/O. |
Beta Was this translation helpful? Give feedback.
-
That solution gets to the heart of it. It's less about the install and more about the dependency download required for install. 👍 |
Beta Was this translation helpful? Give feedback.
-
Just tried with following Dockerfile. FROM node:14-buster
# yq is not availabe from apt yet, install it by copying from the docker image published by its author
COPY --from=mikefarah/yq /usr/bin/yq /usr/bin/yq
RUN npm install -g pnpm
WORKDIR /opt/app
COPY pnpm-lock.yaml ./
# Parse the lockfile add them to store
RUN pnpm store add $(yq -M eval '.packages | keys' pnpm-lock.yaml | sed 's/- \///g' | sed -r 's/\/([^_/]+)(_[^_]+)?$/@\1/g')
COPY package.json pnpmfile.js ./
RUN pnpm i --offline
COPY . ./
RUN pnpm run build Now the building process is much improved, note that the step For monospace project, since there is no easy way to copy only package.json while keep the directory structure, the following Dockerfile works at the best effort. FROM node:14-buster
# yq is not availabe from apt yet, install it by copying from the docker image published by its author
COPY --from=mikefarah/yq /usr/bin/yq /usr/bin/yq
RUN npm install -g pnpm
WORKDIR /opt/app
COPY pnpm-lock.yaml ./
# Parse the lockfile add them to store
RUN pnpm store add $(yq -M eval '.packages | keys' pnpm-lock.yaml | sed 's/- \///g' | sed -r 's/\/([^_/]+)(_[^_]+)?$/@\1/g')
COPY . ./
RUN pnpm m i --offline
RUN pnpm run build @kaidjohnson Hope this could help you. |
Beta Was this translation helpful? Give feedback.
-
Thanks, @thynson! This approach looked promising, but I see the install from a frozen-lockfile taking about half the time as installing to the store and then installing offline. Even if we do get the store hydration layer cached by docker, the offline install is within a margin of error of the frozen lockfile install, so the benefit is undermined by sometimes needing to re-hydrate the store, so it's more expensive to do it this way, unfortunately. Measures: Before After |
Beta Was this translation helpful? Give feedback.
-
Yeah, it seems that your CI environment have much better network bandwidth than ours. Before: While offline installation on host cost around 15s, it seems that the virtual store consturction is relative slow in docker, possibily due to high hard-link creation cost on layered filesystem. See spotify/docker-client#1158. |
Beta Was this translation helpful? Give feedback.
-
Just done an experiment: FROM node:14-buster
RUN npm install -g pnpm
WORKDIR /opt/app
COPY . ./
# Install all packages and then remove all contents except the virtual store
RUN pnpm m i \
&& mv node_modules/.pnpm /virtual-store \
&& rm -rf * \
&& mkdir node_modules && mv /virtual-store node_modules/.pnpm
COPY . ./
# Here the virtual store is already presented
RUN pnpm m i --offline Output (You need to scroll to the most right side to see time costed by each step):
It concludes that if the virtual store is present, and then the installation process can be done very quickly. |
Beta Was this translation helpful? Give feedback.
-
I've created PR #3294 for this feature. |
Beta Was this translation helpful? Give feedback.
-
Original comment
Users of docker can benifit from it, by changing their Dockerfile to
instead of the current popular pattern:
The new Dockerfile pattern will allow pnpm install --ci --only-from-lockfile layer be reused even when package.json is modified, as long as lockfile is not modified, e.g. version bump.
Beta Was this translation helpful? Give feedback.
All reactions