离线环境下不能靠“自定义包名”绕过网络校验,Composer仅认composer.lock中记录且vendor中实际存在的包;包名、版本、哈希值必须严格匹配,否则直接失败;唯一可行的离线包路径重定向方式是path类型仓库或config.vendor-dir全局配置。

离线环境下不能靠“自定义包名”绕过网络校验
离线时 Composer 不会接受任意包名,它只认 composer.lock 里记录的、且本地 vendor/ 中实际存在的包。所谓“自定义包名”(比如把 monolog/monolog 改成 myorg/monolog)在离线场景下毫无意义——Composer 安装时会严格比对包名、版本、哈希值,不匹配直接失败,根本不会尝试映射或别名解析。
真正能生效的包路径重定向只有 installer-paths 和 path 类型仓库
installer-paths 看似像包名映射,但它不是按包名路由,而是按 type 分发。只有满足以下全部条件才触发:
- 目标包的
composer.json明确声明了非library的type(如wordpress-plugin) - 你的项目已安装对应 installer(如
composer/installers) -
extra.installer-paths中的键是相对路径,值中包名必须完全一致("myorg/utils": "plugins/my-utils"✅,"myorg/*": "plugins/"❌) - 普通库(
type: library)写进installer-paths也无效,照样进vendor/
而 path 类型仓库才是本地开发时真正可控的包名“软绑定”方式:
- 在
repositories中配置{"type": "path", "url": "./packages/my-utils"} - 本地包
composer.json的name必须与你require时写的完全一致(如myorg/utils) - 执行
composer require myorg/utils:dev-main,Composer 会把该目录内容复制(或软链,需配"options": {"symlink": true})进vendor/ - 这个过程不联网,不查 Packagist,完全离线可行
config.vendor-dir 是唯一影响所有包安装位置的全局配置
想让所有包(包括自定义包)都进 libs/ 而非默认 vendor/,只能靠 config.vendor-dir:
- 必须写在项目根目录
composer.json的最外层config字段下,如:"config": {"vendor-dir": "libs"} - 值必须是相对路径,不能以
/开头,不支持环境变量 - 改完后必须先删掉旧
vendor/目录,再运行composer install -
autoload.php、bin/下脚本、自动加载映射全都会生成到新路径,但代码里所有require 'vendor/autoload.php'都得手动改成require 'libs/autoload.php'
这个配置对 path 类型仓库也生效——本地包最终也会落到 libs/myorg/utils 下,而不是 vendor/。
离线时最常被忽略的包名一致性陷阱
很多人以为只要 composer.json 里写了 "name": "myorg/utils",就能在别处 require "myorg/utils",其实还差关键一步:
- 本地包的
composer.json必须存在且合法,name字段不能拼错、大小写不能错 - 主项目的
repositories配置中url必须指向该composer.json所在目录(不是上层父目录) -
composer.lock中该包的source类型必须是path,不能是git或dist——否则离线时composer install会因无法校验源而失败 - 如果用了
dev-main这类开发分支版本,确保本地包目录里确实有main分支,且composer.json中没写错version
离线不报错 ≠ 配置正确;真正要验证的,是 vendor/(或你设的 libs/)里是否真出现了对应目录,且 vendor/composer/autoload_psr4.php 中能搜到你的命名空间映射。


















