composer archive 不包含 vendor 目录,仅打包源码,无法直接运行;离线部署需先执行 composer install --no-dev --optimize-autoloader,再用 zip 等命令手动归档 vendor/ 和 autoload.php。

composer archive 命令本身不保留 vendor 目录
直接运行 composer archive 只会打包项目源码(composer.json、composer.lock 和匹配的文件),不会包含 vendor/ 中已安装的依赖。这是它和离线部署需求最根本的错位点——你打出来的 zip 里没有 autoload.php,也没法直接 require 第三方类。
常见错误现象:composer archive 后在目标机器上 php index.php 报 Fatal error: Uncaught Error: Class not found,或 require vendor/autoload.php 失败。
- 它本质是「源码归档」,不是「可运行包」
- 默认只打包
composer.json、composer.lock和.gitignore里没忽略的文件 -
--format=zip或--format=tar不改变这一行为
离线部署必须先 install 再归档 vendor
真正能离线运行的包,得把 vendor/ 连同自动加载器一起打进压缩包。关键不是用什么命令归档,而是归档前的状态。
使用场景:内网服务器无外网访问权限,CI 构建机有网络但目标环境完全隔离。
- 在有网络的机器上执行
composer install --no-dev --optimize-autoloader,确保vendor/完整且 autoloader 高效 - 手动把
vendor/加进归档范围——composer archive不支持,改用系统命令:zip -r app-release.zip . -x "node_modules/*" ".git/*" - 务必包含
composer.lock,否则离线重装时版本漂移风险极高 - 如果用了
composer install --classmap-authoritative,记得确认vendor/composer/autoload_classmap.php存在并生效
archive 命令的唯一合理用途:发布源码包(如私有包分发)
当你需要把一个 Composer 包(比如自研 SDK)发布给其他团队做依赖引用时,composer archive 才是正解——它生成的是别人 require 你的包时 Composer 会下载的源码结构。
参数差异:--exclude 可剔除测试、文档等非运行必需内容;--dir 指定输出路径;但这些都不影响 vendor 是否存在,因为 vendor 本就不该进源码包。
- 典型命令:
composer archive --format=zip --file=my-sdk-1.2.0 --exclude="tests/*,.travis.yml" - 生成的 zip 解压后应能被别人
composer require myorg/my-sdk正常拉取安装 - 如果你把它当部署包用,等于把源码当二进制发过去,必然失败
更稳妥的离线方案:用 deployer 或 rsync + install 脚本
硬打包整个 vendor/ 体积大、易出错(比如符号链接、扩展.so 文件权限)。生产中更推荐「传输源码 + 环境内 install」,只是 install 这步要提前准备好。
性能与兼容性影响:PHP 版本、扩展(如 ext-zip)、composer.lock 中的平台配置(platform)必须严格一致,否则 install 会降级或报错。
- 在目标机器预装相同版本的 Composer,并缓存所有包:
composer config --global cache-dir /shared/composer-cache - 把
composer.lock和composer.json传过去,运行composer install --no-dev --prefer-dist --no-interaction - 若连 dist 包都下不了,就用
composer install --no-dev --prefer-source,前提是 git 可达(比如内网 GitLab)
最易被忽略的一点:很多团队忘了 composer.lock 里的 content-hash 是基于当前 composer.json 计算的,如果归档后改过 JSON 但没重跑 update,install 会拒绝执行——别指望它“差不多就行”。










