Skip to main content
Version: 9.x

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@latest-9

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

# 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" ]

只要 .npmrcpackage.jsonpnpm-lock.yaml.pnpmfile.cjs 没有变化,docker 构建缓存一直有效到 RUN pnpm install --frozen-lockfile --prod 层,这在构建 docker 镜像时花费了大部分时间。

¥As long as there are no changes to .npmrc, package.json, pnpm-lock.yaml, .pnpmfile.cjs, 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.

维护构建 monorepo 项目的 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@latest-9

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

# 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" ]

正如你所看到的,当你添加或删除子包时,Dockerfile 必须更新。

¥As you can see, the Dockerfile has to be updated when you add or remove sub-packages.

pnpm fetch 通过提供仅使用锁定文件中的信息将包加载到虚拟存储中的能力,完美解决了上述问题。

¥pnpm fetch solves the above problem perfectly by providing the ability to load packages into the virtual store using only information from a lockfile.

FROM node:20

WORKDIR /path/to/somewhere

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

# pnpm fetch does require only lockfile
COPY pnpm-lock.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" ]

它适用于简单项目和单一项目,--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.

选项

¥Options

--dev, -D

仅获取开发包

¥Only development packages will be fetched

--prod, -P

不会获取开发包

¥Development packages will not be fetched