持续集成
pnpm 可以很容易地用于各种持续集成系统。
安装 pnpm#
在 GitHub Actions 之外(它有专属的 action),通过独立脚本安装 pnpm:
curl -fsSL https://get.pnpm.io/install.sh | sh -
在 CI 中,有两点让这变得方便:
- **它不需要 Node.js。**pnpm 是一个自包含的可执行文件,并且它可以在后续通过
pnpm runtime set node lts -g为你安装运行时环境,因此一个任务从一开始就不需要依赖 Node.js 镜像。 - **它选择自己的版本。**如果你的
package.json有一个packageManager或者devEngines.packageManager字段,pnpm 会在首次使用时切换到那个版本,因此流水线不在两个地方固定版本。
这个脚本安装到 PNPM_HOME 并追加到 shell 配置文件中,而一个 CI 任务永远不会重新加载。自行声明 PNPM_HOME 并将 $PNPM_HOME/bin 添加到 PATH 中,具体方式根据平台提供的机制而定——下面的示例分别展示了各平台的实现方法。
注意
此页面的早期版本使用了 Corepack。 Corepack 安装了一个 JavaScript 垫片(shim)代替 pnpm,因此每次调用 pnpm 都会在 pnpm 本身启动前启动 Node.js 来运行垫片,每次调用都要付出代价,而 CI 的任务有许多这种代价。安装 pnpm 本身完全避免了这个问题。
注意
在所有提供的配置文件中,存储都被缓存。但是,这不是必需的,并且不能保证缓存的存储会使安装速度更快。因此,不必在作业中缓存 pnpm 存储。
Cache the metadata cache too
Since v11.22.0, pnpm cache path prints the directory pnpm uses for its metadata cache, so a job can cache it without mirroring pnpm's own path resolution. That directory also holds the lockfile verification log, which lets a job skip re-checking an unchanged lockfile against the configured supply-chain policies — the dominant cost of an install in CI once the store is warm.
Important
仅将 pnpm 的 store 和 cache 目录缓存到受信任作业具有写入权限的位置。切勿让不受信任的 CI 任务向存储或元数据缓存写入数据,以免受信任的任务随后将其恢复。这些目录是受信任的缓存;有关详细信息,请参阅 storeDir 和 cacheDir 设置。
CI 中的锁文件行为
当 pnpm 检测到它在 CI 中运行时,它会自动切换到 frozen-lockfile 模式。自 v11 版本以来,pnpm 在 CI 中遇到不兼容的 lockfile 时也会失败——如果 lockfile 是由较新的 pnpm 主版本写入的,则安装会出错,而不是默默地重写它。将你的 CI pnpm 版本升级到与生成 lockfile 时使用的版本一致。
AppVeyor#
在 AppVeyor上,你可以使用 pnpm 安装依赖项,只需将此 添加到你的 appveyor.yml中即可:
environment:
PNPM_HOME: C:\pnpm
install:
- ps: $env:PATH = "$env:PNPM_HOME;$env:PNPM_HOME\bin;$env:PATH"
- ps: Invoke-WebRequest https://get.pnpm.io/install.ps1 -UseBasicParsing | Invoke-Expression
- ps: pnpm install
pnpm 有自己的运行时,因此 Install-Product node 不再需要了。如果你的构建脚本直接调用 node,添加 pnpm runtime set node lts -g 命令。
Azure Pipelines#
在 Azure pipeline 中,你可以将以下内容添加到 Azure-Pipelines.yml 中,使用 pnpm 安装和缓存依赖项:
variables:
pnpm_config_cache: $(Pipeline.Workspace)/.pnpm-store
PNPM_HOME: $(Pipeline.Workspace)/.pnpm
steps:
- task: Cache@2
inputs:
key: 'pnpm | "$(Agent.OS)" | pnpm-lock.yaml'
path: $(pnpm_config_cache)
displayName: Cache pnpm
- script: |
curl -fsSL https://get.pnpm.io/install.sh | sh -
echo "##vso[task.prependpath]$(PNPM_HOME)/bin"
"$(PNPM_HOME)/bin/pnpm" config set store-dir $(pnpm_config_cache)
displayName: "Setup pnpm"
- script: |
pnpm install
pnpm run build
displayName: "pnpm install and build"
task.prependpath 为后续的步骤将 pnpm 放到 PATH 中;在安装 pnpm 的步骤中,通过完整路径调用它。
Bitbucket 流水线#
你可以使用 pnpm 来安装和缓存你的依赖项:
definitions:
caches:
pnpm: $BITBUCKET_CLONE_DIR/.pnpm-store
pipelines:
pull-requests:
"**":
- step:
name: 构建和测试
image: debian:stable-slim
script:
- apt-get update && apt-get install -y --no-install-recommends ca-certificates curl libatomic1 libstdc++6
- export PNPM_HOME="$HOME/.local/share/pnpm"
- export PATH="$PNPM_HOME/bin:$PATH"
- curl -fsSL https://get.pnpm.io/install.sh | sh -
- pnpm config set store-dir "$BITBUCKET_CLONE_DIR/.pnpm-store"
- pnpm runtime set node lts -g
- pnpm install
- pnpm run build # Replace with your build/test…etc. commands
caches:
- pnpm
一个步骤中的所有行都在同一个 shell 中运行,因此 export 会传递给后面的行,并且 store-dir 指向缓存保存的目录。
这个示例从一个空白镜像开始,并且让 pnpm 安装 Node.js。一个最小的镜像需要包含 pnpm 11 可执行文件所依赖的库,即 libatomic1 和 libstdc++6,这类库在 node:24 等镜像中已自带;详见 Linux 运行时要求。 pnpm 12 采用静态链接方式,无需依赖上述库。如果你不想修改你目前的 node 镜像,保留它并且移除 apt-get 和 pnpm runtime set 这几行。
CircleCI#
在 CircleCI 中,你可以将以下内容添加到 .circleci/config.yml 中,使用 pnpm 安装和缓存依赖项:
version: 2.1
jobs:
build: # 这可以是你选择的任何名称
docker:
- image: node:24
resource_class: large
parallelism: 10
environment:
PNPM_HOME: /root/.local/share/pnpm
steps:
- checkout
- restore_cache:
name: 恢复 pnpm 包缓存
keys:
- pnpm-packages-{{ checksum "pnpm-lock.yaml" }}
- run:
name: 安装 pnpm 包管理器
command: |
curl -fsSL https://get.pnpm.io/install.sh | sh -
echo 'export PATH="$PNPM_HOME/bin:$PATH"' >> "$BASH_ENV"
"$PNPM_HOME/bin/pnpm" config set store-dir .pnpm-store
- run:
name: 安装依赖项
command: |
pnpm install
- save_cache:
name: 保存 pnpm 包缓存
key: pnpm-packages-{{ checksum "pnpm-lock.yaml" }}
paths:
- .pnpm-store
CircleCI 会在每个步骤执行前加载 $BASH_ENV,pnpm 正是借此在后续步骤中生效的。
GitHub Actions#
在 GitHub Actions 上,你可以像这样使用 pnpm 安装和缓存你的依赖项(属于 .github/workflows/NAME.yml):
name: pnpm Example Workflow
on:
push:
jobs:
build:
runs-on: ubuntu-24.04
strategy:
matrix:
node-version: [24]
steps:
- uses: actions/checkout@v6
- name: 安装 pnpm 和 Node.js
uses: pnpm/setup@c9883cc79df532ad1a7b81bf9ab944ceb090d65c # v2.0.0
with:
runtime: node@${{ matrix.node-version }}
cache: true
pnpm/setup 会安装 pnpm,然后用它安装指定的运行时,因此不需要单独的 actions/setup-node 步骤。它也会为你运行 pnpm install,并且 cache: true 会在不同运行之间缓存 pnpm 存储。如果你想自己安装依赖项,设置 install: false。
pnpm 版本取自 package.json 中的 packageManager 或 devEngines.packageManager 字段,因此当你更改该版本时,无需更新工作流。如果你的 package.json 中没有声明任一字段,添加一个 version 输入。
GitLab CI#
在 Gitlab 上,您像这样可以使用 pnpm 来安装和缓存你的依赖项 (在 .gitlab-ci.yml 中):
stages:
- build
build:
stage: build
image: node:24.14.1
variables:
PNPM_HOME: "$CI_PROJECT_DIR/.pnpm"
before_script:
- export PATH="$PNPM_HOME/bin:$PATH"
- curl -fsSL https://get.pnpm.io/install.sh | sh -
- pnpm config set store-dir .pnpm-store
script:
- pnpm install # 安装依赖项
cache:
key:
files:
- pnpm-lock.yaml
paths:
- .pnpm-store
Jenkins#
你可以使用 pnpm 来安装和缓存你的依赖项:
pipeline {
agent {
docker {
image 'node:lts-bookworm-slim'
args '-p 3000:3000'
}
}
environment {
PNPM_HOME = "${WORKSPACE}/.pnpm"
PATH = "${PNPM_HOME}/bin:${PATH}"
}
stages {
stage('Build') {
steps {
sh 'curl -fsSL https://get.pnpm.io/install.sh | sh -'
sh 'pnpm install'
}
}
}
}
每个 sh 步骤在它自己的 shell 中运行,因此 PATH 在流水线的 environment 块中设置,而不是在步骤内导出。
Semaphore#
在 Semaphore 上,你可以通过 pnpm 安装并缓存依赖项,只需将此添加到你的 .semaphore/semaphore.yml 文件中:
version: v1.0
name: Semaphore CI pnpm 示例
agent:
machine:
type: e1-standard-2
os_image: ubuntu2404
blocks:
- name: 安装依赖项
task:
env_vars:
- name: PNPM_HOME
value: /home/semaphore/.local/share/pnpm
jobs:
- name: pnpm install
commands:
- export PATH="$PNPM_HOME/bin:$PATH"
- curl -fsSL https://get.pnpm.io/install.sh | sh -
- checkout
- cache restore node-$(checksum pnpm-lock.yaml)
- pnpm install
- cache store node-$(checksum pnpm-lock.yaml) $(pnpm store path)
Travis#
在 Travis CI上,你可以使用 pnpm 安装依赖项,方法是将此 添加到你的 .travis.yml 文件中:
cache:
npm: false
directories:
- "~/.pnpm-store"
env:
global:
- PNPM_HOME="$HOME/.local/share/pnpm"
- PATH="$PNPM_HOME/bin:$PATH"
before_install:
- curl -fsSL https://get.pnpm.io/install.sh | sh -
- pnpm config set store-dir ~/.pnpm-store
install:
- pnpm install