本地包安装慢的根本原因是Composer未禁用远程回退,即使使用path类型仓库仍会联网校验;解决方法是显式配置options和dist、设置COMPOSER_DISABLE_NETWORK=1环境变量,并确保composer.lock完整。

本地包安装慢,基本不是网络问题,而是 Composer 默认仍尝试联网校验、解析或 fallback 到远程源——哪怕你用的是 path 类型的本地仓库。
为什么 path 包安装还卡在 downloading
Composer 对 path 类型仓库(如 "type": "path", "url": "../my-package")默认启用 symlink 模式,但会先尝试读取该目录下的 composer.json,再联网检查是否有更新版本、是否匹配 require 约束、甚至向 packagist.org 发起元数据请求(尤其当 composer.json 里写了 version 字段但未加 dist 配置时)。
- 现象:日志中出现
Downloading https://packagist.org/p/...或Resolving dependencies卡住十几秒 - 根本原因:没禁用远程回退(fallback)、没显式声明离线行为、
composer.json缺少dist描述 - 关键点:
path仓库不等于自动离线;Composer 仍会做版本约束求解和元数据比对,而这些步骤可能触发网络请求
path 仓库必须加 options 和 dist
只写 "type": "path", "url": "../my-package" 是不够的。必须显式关闭联网行为,并告诉 Composer “这就是最终版本,别查了”:
- 在项目
composer.json的repositories中定义时,补全options和dist:
{
"type": "path",
"url": "../my-package",
"options": {
"symlink": true,
"versions": {
"dev-main": "dev-main"
}
},
"dist": {
"type": "zip",
"url": "file:///dev/null",
"reference": "0"
}
}
-
"dist.url": "file:///dev/null"是 trick:强制 Composer 跳过 dist 下载逻辑,避免 fallback 到远程 -
"options.versions"显式映射分支名到版本号,绕过 Composer 自动推导(后者可能触发远程查询) - 确保本地包的
composer.json里有明确version字段(如"version": "dev-main"),否则 Composer 会试图从 Git 获取 commit hash,又可能连网
全局关掉所有远程 fallback 行为
即使用了 path,Composer 在解析依赖图时仍可能查 packagist.org —— 尤其当其他依赖没锁死版本、或 lock 文件缺失时。最彻底的离线方案是临时禁用所有远程源:
- 运行命令前加环境变量:
COMPOSER_NO_INTERACTION=1 COMPOSER_DISABLE_NETWORK=1 - 完整命令示例:
COMPOSER_DISABLE_NETWORK=1 composer install --no-dev --prefer-dist --optimize-autoloader -
COMPOSER_DISABLE_NETWORK=1是硬开关:它让 Composer 完全跳过所有 HTTP 请求,包括元数据获取、版本探测、even GitHub API 调用 - 注意:此模式下必须保证
composer.lock已存在且包含全部path包的完整信息,否则会报错Package not found - 验证是否生效:加
-vvv后看不到任何GET或Downloading日志行
CI/CD 或多环境部署时的缓存陷阱
在 Docker 构建或 CI 中,path 包常被挂载或复制进容器,但 Composer 缓存机制可能误判路径变更,导致反复重解析:
- 问题现象:每次构建都卡在
Resolving dependencies,即使内容完全没变 - 真实原因:
~/.composer/cache里存了基于绝对路径的哈希,容器内路径和宿主机不同,缓存失效 - 解决方法:在构建前清空缓存或禁用路径敏感缓存:
composer config -g cache-files-ttl 0,再运行composer clear-cache - 更稳做法:改用
artifact方式预打包——先在宿主机跑composer archive my/package --format=zip,再把 ZIP 放进dist目录并配置"dist": {"type":"zip","url":"./dist/my-package.zip"},彻底脱离path的路径绑定
真正离线安装的关键不在“本地路径”,而在切断所有隐式网络路径。最容易被忽略的是 COMPOSER_DISABLE_NETWORK=1 这个环境变量——它不像镜像配置那样显眼,但却是唯一能阻止 Composer 在解析阶段偷偷发请求的开关。


















