laravel可安装composer包需满足:根目录含src/及serviceprovider类;composer.json中配置psr-4自动加载、空"laravel.dont-discover";服务提供者以serviceprovider结尾并重写boot()支持publishes;迁移用loadmigrationsfrom,配置发布加tag。

怎么给 Laravel 写一个可安装的 Composer 包
能被 composer require 安装、又能自动注册服务提供者的包,核心不是“写得多漂亮”,而是目录结构和 composer.json 的几处关键字段必须对齐 Laravel 的发现机制。
常见错误现象:composer require yourname/your-package 成功了,但 php artisan vendor:publish 找不到配置,或 AppServiceProvider 里 app()->make(YourClass::class) 报错类不存在——多半是没声明自动发现或服务提供者没注册。
- 根目录下必须有
src/,且至少包含一个服务提供者类(如src/YourPackageServiceProvider.php) -
composer.json中必须有"autoload": { "psr-4": { "YourName\YourPackage\": "src/" } },命名空间和路径严格对应 - 必须声明
"extra": { "laravel": { "dont-discover": [] } }(留空数组表示不屏蔽自动发现),否则 Laravel 9+ 默认跳过扫描 - 如果想支持
vendor:publish,在服务提供者里重写boot()并调用$this->publishes([...], 'your-tag'),同时把配置文件放在src/config/your-config.php
Laravel 10+ 自动发现失效的几个原因
自动发现(Auto-Discovery)不是“写了服务提供者就一定生效”,它依赖 Composer 的 autoload 阶段和 Laravel 启动时的扫描逻辑。一旦断链,包就变成“存在但不可用”。
典型表现:composer install 后 config/app.php 里没自动追加服务提供者,artisan 命令也看不到你的命令。
- 服务提供者类名必须以
ServiceProvider结尾,且命名空间要和composer.json的psr-4规则完全匹配(比如YourNameYourPackageYourPackageServiceProvider) - Composer 的 autoload 信息可能过期:执行
composer dump-autoload -o强制刷新,别只信缓存 - Laravel 会跳过声明了
"laravel": { "dont-discover": ["*"] }或具体包名的扩展包——检查你自己的composer.json和项目根目录的composer.json是否误配 - 本地开发时用
path仓库方式加载包(如"repositories": [{ "type": "path", "url": "../your-package" }]),需确保该路径下有完整的composer.json,且已运行composer update
发布前必须验证的三个兼容性点
一个包在你本地 Laravel 10.42 上跑通,不代表别人装上就没事。Laravel 主版本升级常悄悄改掉底层契约,尤其涉及容器绑定、事件监听和响应构造的地方。
最容易被忽略的是 illuminate/support 版本锁死问题:你用了 Str::of(),但没在 composer.json 里写 "illuminate/support": "^10.0",别人装在 Laravel 9 环境就会报错。
- 在
composer.json的require里明确限定最低 Laravel 版本,例如"laravel/framework": "^10.0|^11.0",不要写^9.0 || ^10.0这种跨大版本的模糊范围 - 避免直接依赖
App或HttpControllers这类应用层命名空间——你的包不该知道用户怎么组织代码 - 如果提供 Artisan 命令,别在
handle()里硬编码config('app.name');改用$this->getLaravel()->make('config')->get('app.name'),否则在某些测试上下文里会取不到值
怎么让 php artisan vendor:publish 只发布你的配置或迁移
用户装了你的包,不一定全都要——有人只要命令,有人只要配置,有人连迁移都不想跑。强制全发,反而增加维护负担和出错概率。
错误做法:在服务提供者里无条件调用 $this->publishes([...]),结果每次 vendor:publish 都弹出一堆选项,用户根本分不清哪个是你家的。
- 给
$this->publishes()第二个参数传一个清晰的 tag,比如'your-package-config'或'your-package-migrations' - 发布时指定 tag:
php artisan vendor:publish --tag=your-package-config,这样用户能精准控制 - 迁移文件必须放在
src/database/migrations,并在服务提供者中用$this->loadMigrationsFrom(__DIR__.'/../database/migrations');——注意是loadMigrationsFrom,不是publishes,否则迁移文件会被复制两次 - 如果配置文件带环境变量占位符(如
'key' => env('YOUR_PACKAGE_KEY', '')),记得在config/app.php的providers数组里确认你的服务提供者已加载,否则env()不会触发加载逻辑











