composer如何避免重复下载相同包?(共享缓存机制说明)

1次阅读

composer install 重复下载包是因默认隔离策略,需启用 cache-vcs 和配置缓存头;验证看终端是否显示“using cached”;ci 中应缓存 ~/.composer/cache 而非 vendor/。

composer如何避免重复下载相同包?(共享缓存机制说明)

composer install 时为什么还在下载已装过的包?

因为默认情况下,Composer 每个项目都维护独立的 vendor/ 目录,不共享下载缓存——哪怕同一个 package、同一版 1.2.3,在不同项目里执行 composer install 仍会重新拉取 ZIP 或克隆 git。这不是 bug,是默认隔离策略。

真正起作用的是 Composer 的全局「artifact cache」和「repository cache」,但它们默认不启用或未配置到位。

  • 本地 ~/.composer/cache/ 确实存在,但只缓存 ZIP 包和元数据,且仅当源支持(如 Packagist)且响应头含 ETag/Last-Modified 才能复用
  • Git 包(vcs 类型)默认每次 clone,除非显式启用 cache-vcs
  • 如果你用的是私有仓库或自建 Satis,没配好 http 缓存头,缓存就形同虚设

怎么开启并验证全局缓存生效?

运行 composer config -g cache-dir ~/.composer/cache 是冗余的(新版默认已设),关键在启用两个开关:

  • 打开 VCS 缓存:composer config -g cache-vcs true —— 这会让 Composer 对 Git 仓库做 shallow clone 并复用 .composer/cache/vcs/ 下的裸仓库
  • 确认元数据缓存可用:composer config -g cache-files-ttl 15552000(6个月),避免频繁刷新 packagist.org 的 packages.json
  • 执行 composer clear-cache 后再 install,观察终端输出:若出现 Downloading <code>vendor/package (1.2.3) 变成 Using cached <code>vendor/package (1.2.3),说明命中

私有包或 Git 仓库下缓存为啥不工作?

因为 Composer 默认把每个 Git URL 当作独立源,https://git.example.com/repo.gitgit@git.example.com:repo.git 被视为两个仓库,缓存不互通;同时,若 Git 服务器禁用了 info/refs?service=git-upload-pack 的缓存头,Composer 就无法判断远程是否有更新,只能强制 fetch。

  • 统一使用 HTTPS 地址,并确保 nginx/apache 返回 Cache-Control: public, max-age=3600
  • composer.json 中显式指定 dist 信息,绕过 Git 操作:
    {     "type": "package",     "package": {         "name": "myorg/mylib",         "version": "dev-main",         "dist": {             "url": "https://releases.myorg.com/mylib-1.2.3.zip",             "type": "zip"         }     } }
  • 避免混用 ssh 和 HTTPS 协议地址,否则 cache-vcs 彻底失效

CI 环境下如何复用缓存避免重复拉取?

CI(如 github Actions、gitlab CI)默认无持久缓存,composer install 每次都是“全新”环境。不能只靠 cache-vcs,得把整个 ~/.composer/cache/ 目录挂载为缓存键。

  • GitHub Actions 示例:用 actions/cache 缓存 ~/.composer/cache 路径,key 基于 composer.lock hash
  • GitLab CI:在 cache: 下配置 key: $CI_COMMIT_REF_SLUG + paths: [ "~/.composer/cache" ]
  • 注意:不要缓存 vendor/,它依赖 PHP 版本和扩展,跨环境不安全;只缓存 Composer 自身的下载产物

最易被忽略的一点:cache-vcs 在容器或 rootless 环境中可能因权限问题静默失败,建议在 CI 启动脚本里加一句 ls -la ~/.composer/cache/vcs/ 确认目录可写且有内容。

text=ZqhQzanResources