pnpm fetch
将包从锁定文件提取到虚拟存储中,包清单将被忽略。
🌐 Fetch packages from a lockfile into virtual store, package manifest is ignored.
使用场景
🌐 Usage scenario
该命令专门用于改进 docker 镜像的构建。
🌐 This command is specifically designed to improve building a docker image.
你可能已经阅读过关于为 Node.js 应用编写 Dockerfile 的[官方指南],如果你还没有阅读,可能想先阅读它。
🌐 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.
从那份指南中,我们学会了为使用 pnpm 的项目编写优化的 Dockerfile,看起来像这样
🌐 From that guide, we learn to write an optimized Dockerfile for projects using pnpm, which looks like
FROM node:20
WORKDIR /path/to/somewhere
RUN corepack enable pnpm && corepack install -g pnpm@next-11
# Files required by pnpm install
COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml .pnpmfile.mjs ./
# If you patched any package, include patches before install too
COPY patches patches
RUN pnpm install --frozen-lockfile --prod
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ]
只要 .npmrc、package.json、pnpm-lock.yaml、pnpm-workspace.yaml、.pnpmfile.mjs 没有变化,docker 构建缓存在 RUN pnpm install --frozen-lockfile --prod 这一层仍然有效,而这层在构建 docker 镜像时消耗了大部分时间。
🌐 As long as there are no changes to .npmrc, package.json, pnpm-lock.yaml, pnpm-workspace.yaml,
.pnpmfile.mjs, docker build cache is still valid up to the layer of
RUN pnpm install --frozen-lockfile --prod, which cost most of the time
when building a docker image.
然而,对 package.json 的修改可能比我们预期的发生得更频繁,因为它不仅包含依赖,还可能包含版本号、脚本以及任何其他工具的任意配置。
🌐 However, modification to package.json may happen much more frequently than
we expect, because it does not only contain dependencies, but may also
contain the version number, scripts, and arbitrary configuration for any other
tool.
维护一个构建单体仓库项目的 Dockerfile 也很困难,它可能看起来像
🌐 It's also hard to maintain a Dockerfile that builds a monorepo project, it may look like
FROM node:20
WORKDIR /path/to/somewhere
RUN corepack enable pnpm && corepack install -g pnpm@next-11
# Files required by pnpm install
COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml .pnpmfile.mjs ./
# If you patched any package, include patches before install too
COPY patches patches
# for each sub-package, we have to add one extra step to copy its manifest
# to the right place, as docker have no way to filter out only package.json with
# single instruction
COPY packages/foo/package.json packages/foo/
COPY packages/bar/package.json packages/bar/
RUN pnpm install --frozen-lockfile --prod
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ]
As you can see, the Dockerfile has to be updated when you add or remove sub-packages.
pnpm fetch 通过提供仅使用锁文件和配置文件(pnpm-workspace.yaml)中的信息将包加载到虚拟存储的能力,完美地解决了上述问题。
FROM node:20
WORKDIR /path/to/somewhere
RUN corepack enable pnpm && corepack install -g pnpm@next-11
# 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
ADD . ./
RUN pnpm install -r --offline --prod
EXPOSE 8080
CMD [ "node", "server.js" ]
它适用于简单项目和 monorepo 项目,--offline 强制 pnpm 不与包注册表通信,因为所需的所有包都已存在于虚拟存储中。
🌐 It works for both simple and monorepo projects, --offline enforces
pnpm not to communicate with the package registry as all needed packages are
already present in the virtual store.
只要锁定文件没有更改,构建缓存在该层(比如 RUN pnpm install -r --offline --prod)之前都是有效的,这将为你节省大量时间。
🌐 As long as the lockfile is not changed, the build cache is valid up to the
layer, so RUN pnpm install -r --offline --prod, will save you much
time.
在执行 pnpm fetch 时,会跳过本地 file: 协议依赖,因为它们引用的目录在获取时可能不可用(例如在 Docker 构建中)。
🌐 Local file: protocol dependencies are skipped during pnpm fetch, since they reference directories that may not be available at fetch time (e.g. in Docker builds).
选项
🌐 Options
--dev, -D
仅获取开发包
🌐 Only development packages will be fetched
--prod, -P
不会获取开发包
🌐 Development packages will not be fetched