Composer无内置查包大小命令,需用du(Linux/macOS)或PowerShell(Windows)统计vendor目录磁盘占用,重点识别非运行时文件,并结合--no-dev、archive.excludes等源头控制优化。

Composer 本身不提供任何查看包大小的命令,composer show、composer show -s、composer show -i 都只输出元数据,不统计磁盘占用——想看谁占空间,必须用系统命令或轻量插件。
用 du 快速定位大包(Linux/macOS)
这是最直接、无依赖、结果最准的方式。关键不是“查包”,而是“查 vendor 下每个目录实际占了多少磁盘”:
- 进项目根目录后执行:
du -sh vendor/* | sort -hr | head -20 - 若发现
symfony/symfony或laravel/framework特别大,别急着删,先ls -la vendor/symfony/symfony看有没有.git、docs/、tests/这类非运行时目录 - 二级命名空间包(如
symfony/console)会落在vendor/symfony/子目录下,单看vendor/*会漏掉,可改用:du -sh vendor/*/vendor/* vendor/*/src vendor/*/lib 2>/dev/null | sort -hr | head -20 -
2>/dev/null是必须加的,否则遇到权限不足或损坏符号链接时命令直接中断
Windows 用户用 PowerShell 替代 du
PowerShell 没有内置 du,但可用原生命令达成同样效果,注意路径和性能:
- 执行:
Get-ChildItem vendor -Directory | ForEach-Object { [PSCustomObject]@{Name=$_.Name; Size=(Get-ChildItem $_.FullName -Recurse -File | Measure-Object Length -Sum).Sum} } | Sort-Object Size -Descending | Select-Object -First 20 - 务必加
-File参数,否则Measure-Object会对目录对象报错 - 如果某包体积显示为
0,大概率是它被软链接指向别处(比如用pathrepo),此时得手动检查vendor/xxx是否为链接:Get-Item vendor/xxx | Select-Object Mode, LinkType
要不要装 baethon/composer-packages-size 插件
这个插件确实能跑出带排序的体积列表,但它只是对 du 的封装,且有隐藏成本:
- 安装需
composer global require baethon/composer-packages-size,全局插件在 CI 或容器中可能未预装,导致命令不可用 - 它扫描的是解压后的全部文件,包括
tests/、.github/、CHANGELOG.md,和你手动du结果一致,没额外信息 - 不支持排除路径(比如你想忽略所有
*.md文件),而find+du组合可以做到 - 如果你已经用
archive.excludes配置跳过了/tests/,那插件显示的体积就比实际部署大——它没感知到“这些文件根本没落地”
为什么单纯看包大小容易误判
一个包显示占 80MB,未必是代码问题;真正要盯的是“哪些内容不该出现在生产环境”:
-
vendor/phpunit/phpunit大,是因为它自带完整二进制、桩类、测试模板,但只要确保它只在require-dev里,并用--no-dev安装,它根本不会出现 -
guzzlehttp/guzzle大,常因包含src/Handler/CurlMultiHandler.php等大量异步逻辑,但你若只用同步请求,其实可以换更轻的psr/http-client实现 - 某些包(如
spatie/browsershot)体积爆炸,是因为嵌入了 Chromium 二进制——这根本不是 PHP 代码,du查出来也没法“优化 autoload”,只能换方案或剥离为独立服务 - 看到
vendor/composer/autoload_classmap.php特别大?说明某个包的classmap扫了整个tests/目录,这时该去改它的composer.json,而不是删文件
真正卡点不在“怎么查”,而在“查完之后删什么、怎么删不破 autoload”。archive.excludes 和 --no-dev 是源头控制,du 只是帮你验证它们是否生效——别让统计数字带偏了优化方向。











