Composer 本身不提供打包功能,composer archive 命令根本不存在;所有可用案例均源于第三方插件或自定义脚本,可靠打包应使用 git archive 结合 composer install --no-dev --optimize-autoloader 手动归档。

Composer 本身不提供打包功能,composer archive 命令根本不存在——所有看到它“能用”的情况,都是误装了第三方插件(比如 hirak/php-archive)或项目里自定义了同名 scripts。真要可靠地打包一个可发布的组件(比如内部通用包),得绕过幻想,直接用组合命令。
为什么不能信 composer archive
执行就会报错:Command "archive" is not defined。这不是版本问题,是官方从未实现。Composer 的职责边界非常清楚:解析 composer.json、下载依赖、生成自动加载器。它不读 .gitattributes,不压缩,不剔除开发文件,也不保证 composer.lock 被包含。一旦你依赖的插件被升级或移除,整个流程就断掉,而你还以为是自己配置错了。
真正可用的打包方式:git archive + composer install
目标是产出一个干净、可复现、带锁文件的源码包(比如用于内部 Satis 仓库或人工分发)。关键不是“一键”,而是“可控”:
- 用
git archive --format=zip --output=package-1.0.0.zip HEAD打包当前 commit,天然排除.git/、vendor/、node_modules/ - 手动把
composer.lock加回去——git archive默认不包含它,但它是生产环境复现依赖的唯一依据 - 如果包需要带
vendor(比如交付给无网络环境),先在干净目录跑:composer install --no-dev --optimize-autoloader,再用zip -r package-with-vendor.zip . -x "tests/*" ".git/*" - 版本号别硬写,用
git describe --tags --abbrev=0或jq -r '.version' composer.json动态提取
如何把打包逻辑固化进 composer.json
避免每次手动敲一串命令,把流程写进 scripts 段,用 composer run deploy:package 触发:
"scripts": {
"deploy:package": [
"git archive --format=zip --output=dist/my-component-$(jq -r '.version' composer.json).zip HEAD",
"zip -u dist/my-component-$(jq -r '.version' composer.json).zip composer.lock"
]
}
注意点:
-
jq需要系统已安装;没有的话改用php -r "echo json_decode(file_get_contents('composer.json'))->version;" -
zip -u是追加模式,确保composer.lock真的进包了 - 不要在脚本里用相对路径如
../my-local-package,打包脚本应假设运行在项目根目录 - 这个脚本只负责“打源码包”,不处理 PSR-4 自动加载验证或单元测试——那些该在 CI 里做,不是打包环节的责任
最常被忽略的一点:打包产物是否包含 composer.lock,直接决定下游项目能否精确还原依赖。很多人图省事跳过这步,结果在内部 Packagist 上发布后,其他项目 composer require 时版本漂移,问题追溯起来极难定位。


















