composer install 后自动清理需通过 scripts 配置自定义命令实现,推荐封装为独立 php 脚本并同时绑定 post-install-cmd 和 post-update-cmd,严格限定清理范围为 tests/、.git/、docs/ 等非运行时目录,避免误删 autoload 相关文件。

Composer install 后自动执行清理脚本的正确姿势
Composer 本身不提供 install 后自动运行清理任务的内置机制,必须靠 scripts 配置 + 自定义命令组合实现。直接写在 post-install-cmd 里看似可行,但容易因执行时机或权限问题失败。
常见错误现象:post-install-cmd 中调用的 shell 命令找不到(如 rm、find),或试图删除 vendor/ 下刚解压的文件导致权限冲突;更隐蔽的是,在 CI 环境中因缓存复用,install 实际走的是 update 流程,post-install-cmd 根本不触发。
- 把清理逻辑封装成独立 PHP 脚本(如
scripts/clean-vendor.php),避免 shell 兼容性问题 - 在
composer.json的scripts段声明:"scripts": { "clean-vendor": "php scripts/clean-vendor.php", "post-install-cmd": ["@clean-vendor"], "post-update-cmd": ["@clean-vendor"] } - 脚本内优先检查
vendor/是否存在且可写,再执行清理;不要硬删vendor/composer/installed.json等 Composer 自维护文件 - 若清理目标是 dev-only 包(如
phpunit),改用--no-dev安装更可靠,而非 install 后再删
哪些文件真该删?别误伤 Composer 运行时依赖
盲目清理 vendor/ 下的 tests/、docs/、.github/ 目录虽能省空间,但可能破坏某些包的自动加载逻辑(尤其当它们通过 autoload.files 引入了测试辅助函数)。
安全清理范围应严格限定在明确无运行时影响的路径:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
-
*/tests/、*/Tests/:绝大多数包的测试目录不参与 autoload -
*/.git/、*/.github/:源码控制元数据,生产环境绝对不需要 -
*/doc/、*/docs/、*/documentation/:文档类目录,除非你的代码主动 require 了其中的 Markdown 渲染器 - 避免删除
*/src/、*/lib/、*/composer.json、*/autoload.php—— 这些是 Composer 解析和加载的关键
CI/CD 中执行清理的兼容性陷阱
GitHub Actions、GitLab CI 默认使用非交互式 shell,rm -rf 或 find -delete 可能因缺少 -f 参数或 find 版本差异报错;Docker 容器中更常见的是 vendor/ 所在挂载卷权限不足,导致脚本静默失败。
- 用
find vendor -name 'tests' -type d -prune -exec rm -rf {} + 2>/dev/null || true替代裸rm,忽略权限错误 - 在 CI 的 job 步骤中显式加一句
ls -la vendor/ | head -n 5,确认清理后结构符合预期(比如phpunit目录是否真的没了) - 若用 Docker 构建镜像,把清理步骤放在
RUN composer install --no-dev --optimize-autoloader之后、COPY . .之前,避免反复解压又删除
替代方案:用 composer-merge-plugin 或自定义 installer 更省事
如果清理目标是统一移除所有包的 tests/,与其每次 install 后扫一遍,不如从源头控制——用 composer/installers 配合自定义安装路径,让 Composer 根本不把 tests/ 下载进来。
不过这需要包作者在 composer.json 中声明 type 并配合 installer 规则,实际项目中不可控因素太多。更现实的做法是:只对明确知道结构的内部包做定制化处理,其余依赖仍走标准清理脚本。
真正难的不是写几行删除命令,而是判断某个目录删掉后会不会让 class_exists('SomeTestHelper') 突然返回 true——这种隐式依赖往往只在特定测试场景下暴露。










