真正有效的组合是composer install --no-dev --optimize-autoloader + archive.excludes配置 + 部署阶段find清理;composer-cleaner不推荐,因其硬删tests/等目录易致Class not found,且无法适配动态加载或命名不统一的路径。

没有“一键干掉冗余文件”的安全工具,真正有效的组合是 composer install --no-dev --optimize-autoloader + archive.excludes 配置 + 部署阶段定向 find 清理;所谓“自动瘦身插件”多数要么功能重叠,要么在运行时暴露类加载错误。
为什么 composer-cleaner 不推荐作为首选
它在 vendor/ 安装完成后扫描并 unlink() 匹配路径(如 /tests/),但无法区分哪些测试目录真能删、哪些不能删:
- monolog/monolog 的
tests/下有Handler示例类,有些项目 runtime 会通过字符串动态加载,删掉直接报Class not found - 它不修改
vendor/autoload.php或 classmap,autoload 仍可能尝试加载已删路径下的文件,错误延迟到运行时才触发 - 对
translations/这类命名不统一的目录硬删,容易漏删或误伤(比如 doctrine/dbal 的翻译藏在lib/Doctrine/DBAL/Tools/Console/Helper/)
archive.excludes 怎么配才真正起效
这个配置只对从 Packagist 下载的 dist 包生效(即 zip/tar.gz 归档),不是所有包都支持。必须按步骤来:
- 先装插件:
composer require --dev composer-archive-excludes - 在
composer.json的config.archive.excludes下写过滤项,路径必须以/开头且结尾,例如:"/tests/"、"/docs/"、"/.github/" - 改完后必须跑
composer update --lock再composer install,否则旧composer.lock会跳过该逻辑 - 它不影响
require-dev中的包——那些得靠--no-dev控制
哪些系统命令能补上 archive.excludes 漏掉的缺口
archive.excludes 对 git clone 的包、本地 path repo、或没维护 .gitattributes 的老包完全无效。这时得靠部署脚本补刀:
- 删文档类文件:
find vendor/ -name "*.md" -o -name "*.txt" -o -name "README*" -o -name "CHANGELOG*" -delete - 删测试目录(加
2>/dev/null忽略权限错误):find vendor/ -path "*/tests" -o -path "*/Tests" -o -path "*/test" -o -path "*/Test" -type d -exec rm -rf {} + 2>/dev/null - 删 Git 元数据:
find vendor/ -name ".git" -type d -exec rm -rf {} + 2>/dev/null - 注意:绝不能删
vendor/autoload.php和vendor/composer/autoload_*.php,否则 autoload 失效
真正要删的是“冗余依赖”,不是“冗余文件”
很多体积问题根源不在文件多,而在装了根本不用的包。比如把 phpunit/phpunit 错放在 require 而非 require-dev,或者留着已弃用的 symfony/var-dumper。这时候该用的是:
-
composer-unused插件:它扫描src/和tests/中的use语句,找出未被引用、也不是其他包必需依赖的包 - 操作流程:
composer require --dev composer-unused/composer-unused→composer unused→ 逐个确认 →composer remove vendor/package-name - 别手动删
vendor/目录或改composer.json后不跑composer remove,否则下次composer update又会拉回来,还可能因锁文件冲突失败
最常被忽略的一点:archive.excludes 和 --no-dev 都只作用于新安装,对已膨胀的 vendor/ 无效;而 composer-unused 不处理文件级冗余,只管包级依赖。三者定位不同,缺一不可。











