TAKASHI YAMASHINA software engineer

pnpmの使い方:高速で効率的なパッケージマネージャー

pnpmは、npmと互換性のある高速なパッケージマネージャーです。ディスク容量を節約し、依存関係のインストールを高速化できます。

インストール方法

npmでインストール

bash
npm install -g pnpm

curlでインストール(推奨)

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

Homebrewでインストール(macOS/Linux)

bash
brew install pnpm

バージョン確認

bash
pnpm --version

基本的な使い方

プロジェクトの初期化

bash
# 新規プロジェクトを作成
pnpm init

# package.jsonが生成される

パッケージのインストール

bash
# package.jsonの依存関係をすべてインストール
pnpm install
# または
pnpm i

パッケージの追加

bash
# 本番用の依存関係として追加
pnpm add <package>

# 例:Expressをインストール
pnpm add express

# 複数のパッケージを追加
pnpm add react react-dom

# 開発用の依存関係として追加
pnpm add -D <package>
# または
pnpm add --save-dev <package>

# 例:TypeScriptを開発用依存関係として追加
pnpm add -D typescript

パッケージの削除

bash
# パッケージを削除
pnpm remove <package>
# または
pnpm rm <package>

# 例:lodashを削除
pnpm remove lodash

パッケージの更新

bash
# すべてのパッケージを更新
pnpm update

# 特定のパッケージを更新
pnpm update <package>

# 例:Reactを更新
pnpm update react

# 最新版に更新(semverの範囲を超えて)
pnpm update --latest

スクリプトの実行

bash
# package.jsonのscriptsを実行
pnpm run <script>

# 例:devスクリプトを実行
pnpm run dev

# 省略形(run不要)
pnpm dev
pnpm test
pnpm build

グローバルインストール

bash
# グローバルにパッケージをインストール
pnpm add -g <package>

# 例:TypeScriptをグローバルにインストール
pnpm add -g typescript

よく使うコマンド

pnpm install(i)

bash
# package.jsonの依存関係をインストール
pnpm install

# pnpm-lock.yamlを無視してインストール
pnpm install --no-frozen-lockfile

# node_modulesを削除してクリーンインストール
rm -rf node_modules pnpm-lock.yaml
pnpm install

pnpm add

bash
# 本番用依存関係として追加
pnpm add express

# 開発用依存関係として追加
pnpm add -D jest

# ピア依存関係として追加
pnpm add -P react

# オプショナル依存関係として追加
pnpm add -O canvas

# 特定のバージョンを指定
pnpm add express@4.18.0

# 最新版を指定
pnpm add express@latest

# バージョン範囲を指定
pnpm add "express@^4.0.0"

pnpm update(up)

bash
# すべてのパッケージを更新
pnpm update

# 対話的に更新するパッケージを選択
pnpm update --interactive

# 最新版に更新
pnpm update --latest
# または
pnpm up -L

# 再帰的に依存関係を更新
pnpm update --recursive

pnpm list(ls)

bash
# インストール済みパッケージを表示
pnpm list

# 最上位の依存関係のみ表示
pnpm list --depth 0

# 特定のパッケージを検索
pnpm list express

# JSON形式で出力
pnpm list --json

# グローバルパッケージを表示
pnpm list -g

pnpm outdated

bash
# 古いパッケージを確認
pnpm outdated

# JSON形式で出力
pnpm outdated --json

pnpm why

bash
# なぜそのパッケージがインストールされているか確認
pnpm why <package>

# 例:lodashがなぜインストールされているか
pnpm why lodash

ワークスペース機能

pnpm-workspace.yaml の作成

pnpm-workspace.yaml yaml
packages:
  - 'packages/*'
  - 'apps/*'

ワークスペースでのパッケージ管理

bash
# すべてのワークスペースで依存関係をインストール
pnpm install

# 特定のワークスペースにパッケージを追加
pnpm add <package> --filter <workspace>

# 例:@myapp/apiワークスペースにexpressを追加
pnpm add express --filter @myapp/api

# すべてのワークスペースでスクリプトを実行
pnpm -r run build

# 並列実行
pnpm -r --parallel run test

ワークスペース内のパッケージ参照

package.json json
{
  "dependencies": {
    "@myapp/utils": "workspace:*"
  }
}
bash
# ワークスペース内のパッケージを追加
pnpm add @myapp/utils --workspace

便利なコマンド

pnpm exec

bash
# node_modules/.binのコマンドを実行
pnpm exec <command>

# 例:tscを実行
pnpm exec tsc

# 省略形(pnpm dlx)
pnpm dlx create-react-app my-app

pnpm dlx

bash
# パッケージをインストールせずに一度だけ実行(npxと同等)
pnpm dlx <package>

# 例:create-viteを実行
pnpm dlx create-vite@latest

pnpm store

bash
# ストアの場所を表示
pnpm store path

# 未使用のパッケージを削除
pnpm store prune

# ストアの状態を確認
pnpm store status

pnpm audit

bash
# 脆弱性をチェック
pnpm audit

# 自動修正
pnpm audit --fix

pnpm patch

bash
# パッケージにパッチを適用
pnpm patch <package>@<version>

# 例:react@18.2.0にパッチを適用
pnpm patch react@18.2.0
# → 一時ディレクトリが作成される
# → ファイルを編集
# → 以下のコマンドを実行
pnpm patch-commit /tmp/patch-dir

pnpm設定

.npmrcで設定

.npmrc plain
# ストアのディレクトリを指定
store-dir=~/.pnpm-store

# symlink(シンボリックリンク)を使用
node-linker=isolated

# フラットなnode_modulesを使用(npmと同じ構造)
node-linker=hoisted

# 厳格なピア依存関係チェック
strict-peer-dependencies=true

# インストール時の進行状況を表示しない
progress=false

# レジストリを指定
registry=https://registry.npmjs.org/

設定コマンド

bash
# 設定を表示
pnpm config list

# 設定を取得
pnpm config get <key>

# 設定を変更
pnpm config set <key> <value>

# 例:ストアディレクトリを変更
pnpm config set store-dir ~/.pnpm-store

# 設定を削除
pnpm config delete <key>

npm/yarnからの移行

package-lock.json / yarn.lock から移行

bash
# npmから移行
pnpm import

# package-lock.jsonからpnpm-lock.yamlが生成される

scripts の置き換え

npmやyarnのscriptsはpnpmでそのまま動作します。

package.json json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "jest"
  }
}
bash
# npm run dev → pnpm dev
pnpm dev

# npm run build → pnpm build
pnpm build

# npm test → pnpm test
pnpm test

実践的な使い方

プロジェクト開始時

bash
# プロジェクトディレクトリを作成
mkdir my-project
cd my-project

# package.jsonを作成
pnpm init

# パッケージを追加
pnpm add express
pnpm add -D typescript @types/node @types/express

# TypeScript設定を作成
pnpm exec tsc --init

既存プロジェクトでの使用

bash
# リポジトリをクローン
git clone https://github.com/user/repo.git
cd repo

# 依存関係をインストール
pnpm install

# 開発サーバーを起動
pnpm dev

パッケージの更新確認と実行

bash
# 古いパッケージを確認
pnpm outdated

# 対話的に更新
pnpm update --interactive

# または、最新版に更新
pnpm update --latest

グローバルパッケージの管理

bash
# グローバルパッケージをインストール
pnpm add -g typescript ts-node nodemon

# グローバルパッケージを確認
pnpm list -g --depth 0

# グローバルパッケージを更新
pnpm update -g typescript

トラブルシューティング

依存関係の競合

bash
# node_modulesとロックファイルを削除して再インストール
rm -rf node_modules pnpm-lock.yaml
pnpm install

キャッシュのクリア

bash
# ストアをクリーンアップ
pnpm store prune

# 完全に削除
rm -rf ~/.pnpm-store

ピア依存関係のエラー

.npmrc plain
# ピア依存関係を自動インストール
auto-install-peers=true

# または、厳格なチェックを無効化
strict-peer-dependencies=false

シンボリックリンクの問題

.npmrc plain
# フラットなnode_modulesを使用
node-linker=hoisted

インストールが遅い場合

bash
# ネットワークの並列実行数を増やす
pnpm install --network-concurrency=10

# または、.npmrcで設定
echo "network-concurrency=10" >> .npmrc

なぜpnpmが高速で効率的なのか

ディスク容量の節約

npmやyarnは、プロジェクトごとにnode_modulesにパッケージをコピーします。pnpmは、グローバルストアに1つだけパッケージを保存し、プロジェクトからはハードリンクを作成します。

plain
# npmの場合
project1/node_modules/react/   (50MB)
project2/node_modules/react/   (50MB)
project3/node_modules/react/   (50MB)
合計: 150MB

# pnpmの場合
~/.pnpm-store/react/            (50MB)
project1/node_modules/react/   → ハードリンク
project2/node_modules/react/   → ハードリンク
project3/node_modules/react/   → ハードリンク
合計: 50MB

インストールの高速化

パッケージがすでにストアにある場合、ネットワークからのダウンロードが不要で、ハードリンクを作成するだけで済みます。

bash
# 初回インストール(ダウンロードが必要)
pnpm install  # 30秒

# 2回目以降(ストアから再利用)
pnpm install  # 5秒

厳格な依存関係管理

pnpmは、package.jsonに明示的に記載された依存関係のみにアクセスできます。npmやyarnでは、直接の依存関係でなくても、他のパッケージの依存関係にアクセスできてしまう問題(Phantom dependencies)がありました。

javascript
// npmの場合(問題あり)
// package.jsonにlodashがなくても動作してしまう
import _ from 'lodash'; // 他のパッケージがlodashに依存している場合

// pnpmの場合(正しく動作)
// package.jsonにlodashがない場合はエラー
import _ from 'lodash'; // Error: Cannot find module 'lodash'

モノレポのサポート

pnpmはワークスペース機能を標準でサポートしており、複数のパッケージを含むモノレポを簡単に管理できます。

pnpm-workspace.yaml yaml
packages:
  - 'packages/*'
  - 'apps/*'
bash
# すべてのワークスペースで依存関係をインストール
pnpm install

# すべてのワークスペースでビルド
pnpm -r run build

npmとpnpmのコマンド対応表

plain
npm                           | pnpm
------------------------------|------------------------------
npm install                   | pnpm install
npm install <package>         | pnpm add <package>
npm install -D <package>      | pnpm add -D <package>
npm install -g <package>      | pnpm add -g <package>
npm uninstall <package>       | pnpm remove <package>
npm update                    | pnpm update
npm run <script>              | pnpm <script>
npx <command>                 | pnpm dlx <command>
npm list                      | pnpm list
npm outdated                  | pnpm outdated
npm audit                     | pnpm audit
npm init                      | pnpm init

yarnとpnpmのコマンド対応表

plain
yarn                          | pnpm
------------------------------|------------------------------
yarn                          | pnpm install
yarn add <package>            | pnpm add <package>
yarn add -D <package>         | pnpm add -D <package>
yarn global add <package>     | pnpm add -g <package>
yarn remove <package>         | pnpm remove <package>
yarn upgrade                  | pnpm update
yarn <script>                 | pnpm <script>
yarn dlx <command>            | pnpm dlx <command>
yarn list                     | pnpm list
yarn outdated                 | pnpm outdated
yarn audit                    | pnpm audit
yarn init                     | pnpm init
yarn workspaces info          | pnpm list -r --depth -1

CIでの使用

GitHub Actions

.github/workflows/ci.yml yaml
name: CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v2
        with:
          version: 8

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Run tests
        run: pnpm test

      - name: Build
        run: pnpm build

GitLab CI

.gitlab-ci.yml yaml
image: node:20

cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - .pnpm-store

before_script:
  - curl -fsSL https://get.pnpm.io/install.sh | sh -
  - pnpm config set store-dir .pnpm-store
  - pnpm install --frozen-lockfile

test:
  script:
    - pnpm test

build:
  script:
    - pnpm build

Dockerでの使用

FROM node:20-alpine

# pnpmをインストール
RUN corepack enable && corepack prepare pnpm@latest --activate

WORKDIR /app

# 依存関係ファイルをコピー
COPY package.json pnpm-lock.yaml ./

# 依存関係をインストール
RUN pnpm install --frozen-lockfile --prod

# ソースコードをコピー
COPY . .

# ビルド
RUN pnpm build

CMD ["pnpm", "start"]

パフォーマンス比較

インストール速度

plain
# 100個の依存関係を持つプロジェクト

npm install(キャッシュなし):  45秒
yarn install(キャッシュなし): 35秒
pnpm install(キャッシュなし): 30秒

npm install(キャッシュあり):  20秒
yarn install(キャッシュあり): 15秒
pnpm install(キャッシュあり): 5秒

ディスク使用量

plain
# 10個のプロジェクトで同じ依存関係を使用

npm:   5.0GB
yarn:  4.5GB
pnpm:  1.2GB

エディタの設定

VS Code

pnpmを使用するプロジェクトでは、VS Codeの設定を調整する必要はありません。ただし、TypeScriptプロジェクトの場合は、workspace版のTypeScriptを使用することを推奨します。

.vscode/settings.json json
{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true
}

WebStorm / IntelliJ IDEA

WebStormやIntelliJ IDEAでは、自動的にpnpmを検出します。手動で設定する場合:

  1. Settings → Languages & Frameworks → Node.js and NPM
  2. Package manager: pnpmを選択

よくある質問

pnpmはnpmと完全に互換性があるか?

はい、pnpmはnpmと完全に互換性があります。package.jsonの形式も同じで、npmのscriptsもそのまま動作します。

既存プロジェクトをpnpmに移行すべきか?

以下の場合、pnpmへの移行を検討してください:

pnpmで問題が発生した場合は?

まず、node_modulesとロックファイルを削除して再インストールを試してください。それでも解決しない場合は、.npmrcnode-linker=hoistedを設定してnpmと同じ構造を使用できます。