跳到主内容
版本:11 & 12

持续集成

pnpm 可以很容易地用于各种持续集成系统。

Installing pnpm

Outside of GitHub Actions, which has its own action, install pnpm with the standalone script:

curl -fsSL https://get.pnpm.io/install.sh | sh -

Two things make this convenient in CI:

  • It needs no Node.js. pnpm is a self-contained executable, and it can install the runtime for you afterwards with pnpm runtime set node lts -g, so a job does not need a Node.js image to begin with.
  • It picks its own version. If your package.json has a packageManager or devEngines.packageManager field, pnpm switches to that version on first use, so the pipeline does not pin a version in two places.

The script installs into PNPM_HOME and appends to a shell profile, which a CI job never reloads. Declare PNPM_HOME and put $PNPM_HOME/bin on PATH yourself, using whatever mechanism the platform provides — the examples below show it for each one.

注意

Earlier versions of this page used Corepack. Corepack installs a JavaScript shim in place of pnpm, so every pnpm call starts Node.js to run the shim before pnpm itself starts — a cost paid on each invocation, and CI jobs make many of them. Installing pnpm itself avoids that entirely.

Corepack also cannot install pnpm 12: it expects the package to contain a bin/pnpm.mjs, which the native pnpm 12 package does not have.

注意

在所有提供的配置文件中,存储都被缓存。 但是,这不是必需的,并且不能保证缓存的存储会使安装速度更快。 因此,不必在作业中缓存 pnpm 存储。

important

仅将 pnpm 的 store 和 cache 目录缓存到受信任作业具有写入权限的位置。 切勿让不受信任的 CI 任务向存储或元数据缓存写入数据,以免受信任的任务随后将其恢复。 These directories are trusted caches; see the storeDir and cacheDir settings for details.

CI 中的锁文件行为

当 pnpm 检测到它在 CI 中运行时,它会自动切换到 frozen-lockfile 模式。 自 v11 版本以来,pnpm 在 CI 中遇到不兼容的 lockfile 时也会失败——如果 lockfile 是由较新的 pnpm 主版本写入的,则安装会出错,而不是默默地重写它。 将你的 CI pnpm 版本升级到与生成 lockfile 时使用的版本一致。

AppVeyor

AppVeyor 上,在你的 appveyor.yml 中添加这些来使用 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 brings its own runtime, so Install-Product node is no longer needed. Add pnpm runtime set node lts -g if your build scripts call node directly.

Azure Pipelines

在 Azure pipeline 中,你可以将以下内容添加到 Azure-Pipelines.yml 中,使用 pnpm 安装和缓存依赖项`:

azure-pipelines.yml
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 puts pnpm on PATH for the steps that follow; within the step that installs it, call it by its full path.

Bitbucket Pipelines

You can use pnpm for installing and caching your dependencies:

.bitbucket-pipelines.yml
definitions:
caches:
pnpm: $BITBUCKET_CLONE_DIR/.pnpm-store

pipelines:
pull-requests:
"**":
- step:
name: Build and test
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

All the lines of a step run in one shell, so export carries to the ones that follow, and store-dir is pointed at the directory the cache saves.

This example starts from a plain image and lets pnpm install Node.js. A minimal image needs the libraries the pnpm 11 executable links against — libatomic1 and libstdc++6 — which images like node:24 already carry; see Linux runtime requirements. pnpm 12 is statically linked and needs neither. Keep your existing node image and drop the apt-get and pnpm runtime set lines if you would rather not change it.

CircleCI

在 CircleCI 中,你可以将以下内容添加到 .circleci/config.yml 中,使用 pnpm 安装和缓存依赖项`:

.circleci/config.yml
version: 2.1

jobs:
build: # this can be any name you choose
docker:
- image: node:24
resource_class: large
parallelism: 10
environment:
PNPM_HOME: /root/.local/share/pnpm

steps:
- checkout
- restore_cache:
name: Restore pnpm Package Cache
keys:
- pnpm-packages-{{ checksum "pnpm-lock.yaml" }}
- run:
name: Install pnpm package manager
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: Install Dependencies
command: |
pnpm install
- save_cache:
name: Save pnpm Package Cache
key: pnpm-packages-{{ checksum "pnpm-lock.yaml" }}
paths:
- .pnpm-store

CircleCI sources $BASH_ENV before every step, which is how pnpm reaches the steps that follow.

GitHub Actions

在 GitHub Actions 上,你可以像这样使用 pnpm 安装和缓存你的依赖项(属于 ·.github/workflows/NAME.yml·):

.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: Install pnpm and Node.js
uses: pnpm/setup@c9883cc79df532ad1a7b81bf9ab944ceb090d65c # v2.0.0
with:
runtime: node@${{ matrix.node-version }}
cache: true

pnpm/setup installs pnpm, then uses it to install the requested runtime, so no separate actions/setup-node step is needed. It also runs pnpm install for you, and cache: true caches the pnpm store between runs. Set install: false if you would rather run the install yourself.

The pnpm version comes from the packageManager or devEngines.packageManager field of your package.json, so the workflow never needs updating when you change it. Add a version input if your package.json declares neither.

GitLab CI

在 Gitlab 上,你可以像这样使用 pnpm 来安装和缓存你的依赖项(在 .gitlab-ci.yml 中):

.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 # install dependencies
cache:
key:
files:
- pnpm-lock.yaml
paths:
- .pnpm-store

Jenkins

You can use pnpm for installing and caching your dependencies:

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'
}
}
}
}

Each sh step runs in its own shell, so PATH is set in the pipeline's environment block rather than exported inside a step.

Semaphore

在 [Semapore] 上,请将此内容添加到 .semaphore/semaphore.yml 文件中以使用 pnpm 来安装和缓存你的依赖:

.semaphore/semaphore.yml
version: v1.0
name: Semaphore CI pnpm example
agent:
machine:
type: e1-standard-2
os_image: ubuntu2404
blocks:
- name: Install dependencies
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 上,请将此添加到你的 .travis.yml 文件中以使用 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