開発プロジェクトのテックリードとして、チーム全体の生産性を極限まで引き上げるための知見を共有しよう。
PHPの依存関係管理において、日頃何気なく打っている `composer install` や `composer update`。君は、その裏側でComposerの依存関係解決エンジンがどのように動き、どのパッケージソースを選択しているかを意識したことがあるだろうか。
「とりあえず動くからディストリビューション(zip)でいいや」「たまにソースコードを直接いじりたいから `–prefer-source` かな」――もしそう考えているなら、大規模な開発現場やCI/CDパイプラインにおいて、手痛いパフォーマンスの低下や、デバッグの迷宮に迷い込むリスクを抱えていることになる。
今回は、Composerの心臓部であるパッケージインストール戦略、特に `–prefer-source` と `–prefer-dist` の技術的深層と、環境別の最適解 について、アーキテクトの視点から徹底的に解剖する。
—
1. 内部メカニズムの解剖:`–prefer-source` vs `–prefer-dist`
まずは、これら2つのフラグがComposerの内部で何を引き起こしているのか、そのデータフローと実態を明確にする。
`–prefer-dist` (デフォルト戦略)
- 動作原理: Packagist等のリポジトリから、タグやブランチに対応するアーカイブ(通常は `.zip` や `.tar.gz`)をHTTP経由でダウンロードし、展開する。
- メリット:
- ダウンロードサイズが極めて小さい(余分なGitメタデータが含まれない)。
- 展開処理が高速であり、I/O負荷が低い。
- デメリット:
- `.git` ディレクトリが存在しないため、パッケージ自体のコードを直接修正してコミットを飛ばすようなアプローチ(いわゆる「ベンダーハック」)が不可能。
`–prefer-source`
- 動作原理: パッケージのソースリポジトリ(GitHub等)を直接 `git clone`(またはすでにキャッシュがある場合は `git fetch` 後のチェックアウト)し、開発者モード(あるいはそれに準ずる状態)で配置する。
- メリット:
- パッケージ内に完全な `.git` リポジトリが生成される。
- サードパーティライブラリのバグをその場で修正し、独自パッチとしてブランチを切ったり、ローカルで差分(`git diff`)を取ったりすることが容易になる。
- デメリット:
- クローン処理のネットワーク負荷およびディスクI/Oが圧倒的に重い。
- CI環境などでこれを多用すると、GitHubのAPIレートリミット(認証なしの場合)に容易に抵触し、ビルドが爆発する。
—
2. 環境別に使い分ける極意:アーキテクトの判断基準
開発効率とCI/CDの堅牢性を最大化するためには、環境の目的に応じてこの戦略を明確にスイッチングする必要がある。
ローカル開発環境(Local Development)
- 推奨戦略: `–prefer-source` (またはプロジェクトの性質により選択)
- 理由:
フレームワークのコアやミドルウェア、あるいは自社製のプライベートパッケージにバグを見つけた際、`vendor/package-name` 内に直接潜って原因究明と修正を行うケースがある。`–prefer-source` で入れておけば、そのままローカルリポジトリとして操作できるため、修正の検証スピードが桁違いに向上する。
本番・ステージング・CI/CD環境(Production / CI)
- 推奨戦略: `–prefer-dist` (一択)
- 理由:
ビルドの速度と再現性が命である。`.git` メタデータは本番稼働において完全なノイズであり、セキュリティ面(万が一のGit設定ファイルの露出リスク)からも排除すべきである。また、後述するCIキャッシュのヒット率を最大化するためにも、軽量なzip配布である `–prefer-dist` が絶対要件となる。
—
3. 実践:チーム開発を加速する `composer.json` のベストプラクティス構成
チーム全体でこの挙動を意識せずとも、リポジトリ側でデフォルトの挙動をコントロールし、さらに開発体験を爆発的に高めるための `composer.json` の設定例を提示する。
以下の設定は、Autoloadの最適化、GitHub APIのトークン連携によるレートリミット回避、およびプラグインによる快適な開発環境の構築を網羅したプロダクションクオリティの設定である。
{
“name”: “enterprise/core-application”,
“description”: “High-performance backend application with optimized Composer configuration.”,
“type”: “project”,
“license”: “proprietary”,
“require”: {
“php”: “^8.2”,
“laravel/framework”: “^10.0”,
“guzzlehttp/guzzle”: “^7.5”
},
“require-dev”: {
“barryvdh/laravel-ide-helper”: “^2.13”,
“friendsofphp/php-cs-fixer”: “^3.14”,
“nunomaduro/larastan”: “^2.0”
},
“config”: {
“optimize-autoloader”: true,
“classmap-authoritative”: true,
“preferred-install”: {
“”: “dist”,
“my-company/internal-core-sdk”: “source”
},
“sort-packages”: true,
“allow-plugins”: {
“pestphp/pest-plugin”: true,
“phpstan/extension-installer”: true
}
},
“scripts”: {
“post-autoload-dump”: [
“@php artisan package:discover –ansi”
],
“dev:setup”: [
“composer install –prefer-source”,
“@php artisan key:generate –ansi”
],
“ci:install”: [
“composer install –prefer-dist –no-dev –no-progress –no-interaction”
]
}
}
設定値の深掘り解説
1. `config.preferred-install` の高度な使い分け:
- `””: “dist”` により、原則すべてのサードパーティパッケージは高速なzip(dist)でインストールする。
- ただし `”my-company/internal-core-sdk”: “source”` のように特定の自社製プライベートパッケージのみを `source` 指定することで、社内ライブラリの開発と本体アプリのデバッグをシームレスに結合できる。
2. `classmap-authoritative: true`:
- 本番環境におけるオートロードのパフォーマンスを限界まで引き上げる。ファイルシステムのスキャンを完全に抑制し、クラスマップのみで解決させることで数ミリ秒単位のオーバーヘッドを削る。
3. カスタムスクリプト (`dev:setup` と `ci:install`):
- ローカル開発者向けには `–prefer-source` を明示したセットアップコマンドを用意し、CI環境向けには `–no-dev` と `–prefer-dist` を組み合わせた堅牢かつ高速なビルドコマンドを定義。これにより人的ミスによる環境差異を完全に排除する。
—
4. 現場で震えるほど役立つ:CI/CDキャッシュの極意とトラブルシューティング
GitHub Actions等のCI環境で Composer のキャッシュを効率化する際、`–prefer-dist` の恩恵が最大限に活きる。以下に、最高速で動作する GitHub Actions のワークフロー断片を示す。
name: Backend CI/CD Pipeline
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ‘8.2’
tools: composer:v2
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo “dir=$(composer config cache-files-dir)” >> $GITHUB_OUTPUT
- name: Cache Composer Dependencies
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${