根本原因是composer在monorepo中默认重复解析所有包的composer.json并执行冗余操作,尤其path仓库引发大量i/o和symlink扫描,导致耗时从几秒升至数分钟。

为什么 composer install 在 Monorepo 里特别慢?
根本原因不是 Composer 本身变慢,而是默认行为在 Monorepo 场景下被严重放大:每次运行都会完整解析所有 composer.json(包括 workspace 内几十个包),重复执行依赖图计算、版本约束比对、锁文件校验。尤其当本地开发包通过 path 类型仓库引用时,Composer 还会逐个扫描对应目录的 composer.json 并尝试 symlink,I/O 和逻辑开销叠加导致耗时陡增。
常见现象:composer install 耗时从几秒升至 2–5 分钟;composer update 几乎无法在 CI 中稳定通过;本地改一个包,其他包也触发冗余安装。
- 确认是否真由 Monorepo 引起:临时删掉
repositories中的path条目,再跑一次composer install,对比耗时 - 检查是否启用了
composer-plugin-api类插件(如symfony/flex),它们可能在每个包路径上重复执行钩子 - 避免在根
composer.json中用"*"或模糊约束(如"^1.0")引用 workspace 内部包——这会让 Composer 拒绝复用已安装的 symlink,强制重解
只安装当前项目需要的包:--no-install + --no-autoloader 组合用法
Monorepo 的核心矛盾在于「根项目不需要所有 workspace 包都装到 vendor/」。例如你只在调试 packages/utils,却让 Composer 把 packages/api-client、packages/db-layer 全部 symlink 进来,纯属浪费。
正确做法是分层控制:
- 根目录只声明「顶层应用依赖」,所有
packages/*都移出require,改用repositories+path声明为本地源 - 各
packages/*目录下保持独立composer.json,含完整require-dev和测试依赖 - 日常开发用:
cd packages/utils && composer install --no-install --no-autoloader—— 此时只生成vendor/autoload.php,不下载任何包,靠根项目的 autoload 映射加载 - CI 构建单个包时,才进对应目录执行完整
composer install
注意:--no-install 不会跳过 require-dev 的安装,如需彻底跳过,得加 --no-dev;但通常开发时仍需 phpunit 等工具,所以保留 --no-dev 反而容易漏测。
composer config 关键调优项(非全局!)
Monorepo 下最有效的提速配置都在根 composer.json 的 config 字段里,且必须显式关闭某些默认行为:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
-
"fxp-asset": false—— 如果没用bower-asset或npm-asset,务必关掉,否则 Composer 会额外发起大量 HTTP 请求校验 -
"preferred-install": "dist"—— 强制走 zip 包而非 git clone,尤其对path类型无效,但能防止意外 fallback 到慢速方式 -
"autoloader-suffix": "Monorepo"—— 避免和非 Monorepo 项目共用vendor/autoload.php缓存,减少 autoloader 冲突风险 -
"disable-tls": true仅限内网可信环境(如 GitLab CE 自托管),可省去 SSL 握手开销,但生产环境禁用
别碰 cache-dir:Monorepo 多项目共享缓存反而易出错,Composer 默认的 ~/.composer/cache 已足够高效。
CI/CD 中避免重复解析:用 composer install --no-scripts --no-plugins
CI 流水线里最常踩的坑是把本地开发习惯照搬到构建阶段——比如在根目录跑 composer install,结果触发所有 post-install-cmd(如生成 classmap、dump-autoload),而这些脚本在 Monorepo 里往往跨包执行,耗时翻倍。
CI 构建应严格按需:
- 构建 PHP 应用镜像时:进
app/目录,composer install --no-dev --no-scripts --no-plugins --optimize-autoloader - 运行单元测试前:进
packages/logger,composer install --no-scripts(只需 autoload,无需执行post-autoload-dump) - 永远不要在根目录执行
composer update—— 锁文件应由开发者在本地维护,CI 只负责install
如果某个包必须运行 post-install-cmd(如生成配置模板),把它移到该包自己的 scripts 里,并在 CI 中显式调用:composer run-script post-install-cmd,而不是依赖全局 install 触发。
Monorepo 的依赖速度瓶颈,从来不在网络或磁盘,而在 Composer 对「项目边界」的误判。一旦接受「根目录不是项目,只是协调器」这个前提,优化路径就非常清晰:切断不必要的解析链路,让每个命令只做它该做的事。










