CI中Composer install慢的根源是每次重建vendor目录且无有效缓存;提速关键在于基于composer.lock哈希精准缓存vendor目录,并配合--no-interaction、--prefer-dist、--optimize-autoloader等参数。

Composer install 为什么在CI中特别慢?
因为默认每次都会重新下载所有依赖包,尤其是 vendor/ 目录完全重建,且没有复用已有的 PHP 扩展缓存或 Composer 自身的 global cache。CI 环境通常不保留上一次构建的文件,导致重复拉取相同版本的包(比如 monolog/monolog v2.13.0),网络+解压+安装三重开销叠加。
用 --no-interaction 和 --prefer-dist 是基础但不够
这两个参数能跳过交互提示、强制走压缩包而非 Git 克隆,属于必须项,但无法解决“每次重下”的本质问题。真正提速靠的是缓存策略组合:
-
--no-interaction --prefer-dist --optimize-autoloader --classmap-authoritative:减少运行时 autoload 开销,适合生产环境 CI - 必须配合
composer install前的缓存 restore 步骤,否则参数再优也白搭 - 注意
composer.lock文件必须提交到仓库,否则缓存失效或版本漂移
GitHub Actions 中缓存 vendor 目录最稳的方式
直接缓存 vendor/ 目录比缓存 Composer 的 global cache 更可靠——因为后者受 PHP 版本、扩展、composer.json 配置(如 platform)影响大,容易误命中;而 vendor/ 缓存只依赖 composer.lock 的 hash,精准度高。
steps:
- uses: actions/checkout@v4
- name: Cache vendor directory
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
- name: Install dependencies
run: composer install --no-interaction --prefer-dist --optimize-autoloader --classmap-authoritative
关键点:key 必须包含 hashFiles('**/composer.lock'),不能只用 PHP 版本或 OS;否则 lock 文件一变,旧缓存仍被复用,导致依赖不一致。
GitLab CI 里用 cache: key + policy 要避开路径陷阱
GitLab 不支持像 GitHub 那样自动 hash 文件内容,得手动用 script 计算 lock 文件 hash,并确保 cache: 块中的 key: 和 paths: 严格匹配:
before_script: - export COMPOSER_CACHE_DIR="$CI_PROJECT_DIR/.composer-cache" - mkdir -p $COMPOSER_CACHE_DIRcache: key: ${CI_COMMIT_REF_SLUG}-composer-${CI_JOB_NAME}-${CI_PIPELINE_ID} paths:
- vendor/
- .composer-cache/
stages:
- build
build-job: stage: build script:
- |
if [ -f composer.lock ]; then
LOCK_HASH=$(sha256sum composer.lock | cut -d' ' -f1)
echo "Using composer.lock hash: $LOCK_HASH"
实际缓存 key 应该基于这个 hash,但 GitLab 不支持动态 key,所以建议用 include+template 或外部工具生成
fi
- composer install --no-interaction --prefer-dist --optimize-autoloader
真实项目中更推荐把
vendor/放进cache: paths:并用固定 key(如composer-${CI_COMMIT_REF_SLUG}),同时在script开头加校验逻辑:如果vendor/autoload.php存在但composer install报错 “package not found”,说明缓存脏了,需加rm -rf vendor清理后重装。缓存不是开了就快,关键是让缓存 key 精确反映依赖状态;
composer.lock变了,缓存就必须失效——这点最容易被忽略,也是 CI 中出现“本地好使、CI 报错”的常见根源。










