CI中应缓存~/.composer/cache而非vendor/,因其包含files、repo、vcs等子目录,其中files和repo对加速最关键;GitHub Actions需用actions/cache@v3并以hashFiles('**/composer.lock')等构建缓存key。

CI中缓存Composer全局cache目录的关键路径
CI系统真正该缓存的是~/.composer/cache,不是vendor/。缓存vendor/看似快,但会绕过Composer的依赖解析逻辑,导致lock文件变更时失效、dev依赖误入生产环境、甚至自动加载映射错乱。
这个路径下包含四个子目录:files(下载的zip/tar包)、repo(Packagist元数据)、vcs(Git clone缓存)、archived(已废弃,可忽略)。其中files和repo对提速影响最大。
- GitHub Actions必须用
actions/cache@v3,且key要包含hashFiles('**/composer.lock'),否则缓存无法命中 - GitLab CI需在
cache:块中显式声明paths: [ "$HOME/.composer/cache" ],不能只写~/.composer/cache - 缓存key里加
runner.os或CI_OS变量,避免Linux镜像误用macOS缓存引发解压失败
composer install命令必须带的三个参数
仅缓存目录还不够,composer install命令本身若没配对参数,缓存利用率会暴跌——比如不加--prefer-dist,Composer就可能回退到--prefer-source,触发Git clone,完全绕过files缓存。
-
--no-interaction:禁用所有交互提示,否则CI卡在“Do you trust this repository?”之类的问题上 -
--prefer-dist:强制走压缩包分发渠道,跳过vcs目录,100%命中files缓存 -
--no-dev:生产环境部署时必须排除require-dev,否则缓存体积膨胀30%以上,且增加安全风险
漏掉任意一个,都可能导致CI耗时从20秒飙升到3分钟。
缓存失效的两个隐藏陷阱
缓存命中的前提是“相同输入产生相同输出”,但有些操作会悄悄破坏这个前提,且错误现象不报错,只表现为速度没提升。
- 本地执行过
composer update再提交composer.lock:新lock文件里的哈希值变了,但CI缓存key没变——因为key只看lock文件内容,而lock文件内容本身已更新。解决方案是让缓存key包含hashFiles('**/composer.lock')的完整哈希,而非文件名 - CI runner重装PHP版本:不同PHP版本生成的
autoload_classmap.php二进制不兼容,但Composer不会报错,只会默默重新生成。应在缓存key中加入php -v输出的主版本号,例如php-8.2
私有包仓库的缓存适配要点
如果项目用了私有Git仓库或Satis服务,~/.composer/cache/vcs就变得关键。但默认配置下,这个目录不会被CI缓存策略覆盖——因为它的路径是动态生成的,形如~/.composer/cache/vcs/https---git.example.com-my-private-repo.git/。
- 必须在
composer.json中显式配置"cache-vcs-dir",把它固定到~/.composer/cache/vcs根下,否则每个私有库都会创建独立子目录,缓存无法复用 - 私有仓库认证凭据(如
auth.json)不能硬编码在CI脚本里,要用环境变量注入,并确保auth.json本身也纳入缓存路径,否则每次认证失败都触发重新clone - 使用
composer config --global github-oauth.github.com $GITHUB_TOKEN比放auth.json更安全,且Token变更时只需刷新缓存key,不用重建整个cache目录
私有包场景下,缓存设计稍有偏差,就容易变成“看起来在缓存,实际每轮都在重下”。关键得盯住vcs子目录是否真被复用,而不是只看总耗时下降了没。


















