跳到主要内容
版本:10.x

pnpm 获取

从锁文件获取包到虚拟存储中,忽略包清单。

使用场景

该命令专门用于优化 Docker 镜像构建。

你可能已经阅读过编写 Node.js 应用 Dockerfile 的官方指南,如果尚未阅读,建议先查看。

从该指南中,我们了解到使用 pnpm 的优化 Dockerfile 应该如下所示:

FROM node:20

WORKDIR /path/to/somewhere

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

# pnpm install 需要的文件
COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml .pnpmfile.cjs ./

# 如果修补过任何包,在安装前也需要复制补丁
COPY patches patches

RUN pnpm install --frozen-lockfile --prod

# 打包应用源码
COPY . .

EXPOSE 8080
CMD [ "node", "server.js" ]

只要 .npmrcpackage.jsonpnpm-lock.yamlpnpm-workspace.yaml.pnpmfile.cjs 没有变化,Docker 构建缓存在 RUN pnpm install --frozen-lockfile --prod 这一层仍然有效,这正是构建 Docker 镜像最耗时的步骤。

然而,package.json 的修改频率可能比预期更高,因为它不仅包含依赖信息,还可能包含版本号、脚本和任意其他工具的配置。

维护单体仓库项目的 Dockerfile 也很困难,它可能看起来像这样:

FROM node:20

WORKDIR /path/to/somewhere

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

# pnpm install 需要的文件
COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml .pnpmfile.cjs ./

# 如果修补过任何包,在运行 pnpm install 前也需要包含补丁
COPY patches patches

# 对于每个子包,我们必须添加额外步骤将其清单复制到正确位置,因为 Docker 无法通过单条指令过滤出仅包含 package.json 的文件
COPY packages/foo/package.json packages/foo/
COPY packages/bar/package.json packages/bar/

RUN pnpm install --frozen-lockfile --prod

# 打包应用源码
COPY . .

EXPOSE 8080
CMD [ "node", "server.js" ]

如你所见,当添加或移除子包时必须更新 Dockerfile。

pnpm fetch 通过仅使用锁文件和配置文件(pnpm-workspace.yaml)加载包到虚拟存储中,完美解决了上述问题。

FROM node:20

WORKDIR /path/to/somewhere

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

# pnpm fetch 仅需要锁文件
COPY pnpm-lock.yaml pnpm-workspace.yaml ./

# 如果修补过任何包,在运行 pnpm fetch 前也需要包含补丁
COPY patches patches

RUN pnpm fetch --prod


ADD . ./
RUN pnpm install -r --offline --prod


EXPOSE 8080
CMD [ "node", "server.js" ]

它适用于简单项目和单体仓库项目,--offline 参数强制 pnpm 不与包注册表通信,因为所需包已存在于虚拟存储中。

只要锁文件未更改,构建缓存就有效,因此 RUN pnpm install -r --offline --prod 将节省大量时间。

选项

--dev, -D

仅获取开发依赖包

--prod, -P

不获取开发依赖包