spatie/laravel-package-tools
A base PackageServiceProvider for Laravel package authors to quickly register and publish config, views, translations, assets, routes, migrations, commands, view components/composers, and an optional interactive install command.
Installation:
composer require spatie/laravel-package-tools --dev
Add to your composer.json under require-dev (critical for package development).
First Use Case:
Replace your package’s ServiceProvider with PackageServiceProvider:
use Spatie\LaravelPackageTools\PackageServiceProvider;
use Spatie\LaravelPackageTools\Package;
class YourPackageServiceProvider extends PackageServiceProvider
{
public function configurePackage(Package $package): void
{
$package->name('your-package')
->hasConfigFile()
->hasViews()
->hasMigration('create_your_package_table')
->hasCommand(YourCommand::class);
}
}
Key Files to Review:
config/your-package.php (auto-generated by hasConfigFile())database/migrations/ (auto-published by hasMigration())resources/views/vendor/your-package/ (auto-published by hasViews())Package Registration:
configurePackage() to declare package assets (config, migrations, views, commands, etc.).$package->name('your-package')
->hasConfigFile()
->hasViews()
->hasCommand(InstallCommand::class);
Asset Publishing:
config/ via php artisan vendor:publish --provider="YourPackageServiceProvider".--tag="your-package":
php artisan vendor:publish --tag="your-package" --provider="YourPackageServiceProvider"
Commands:
Spatie\LaravelPackageTools\Commands\Concerns\WithNameInput for CLI flags.configurePackage():
$package->hasCommand(YourCommand::class);
Testing:
Spatie\LaravelPackageTools\Tests\CreatesApplication trait for package tests:
use Spatie\LaravelPackageTools\Tests\CreatesApplication;
class YourPackageTest extends TestCase
{
use CreatesApplication;
public function test_example()
{
// Test logic here
}
}
Publishing Assets:
boot() to publish assets conditionally:
public function boot()
{
$this->publishes([
__DIR__.'/../config/your-package.php' => config_path('your-package.php'),
], 'config');
}
Package Discovery:
Spatie\LaravelPackageTools\Package::discoverFor() to load package config dynamically:
$package = Package::discoverFor('your-package');
Asset Overwriting:
--force may fail if files exist. Use:
php artisan vendor:publish --tag="your-package" --force
--ansi to see diffs before overwriting.Command Registration:
Spatie\LaravelPackageTools\Commands\Concerns\WithNameInput for proper flag handling.Testing Quirks:
CreatesApplication trait resets Laravel’s service container. Avoid testing singleton bindings directly.app()->singleton() in tests if needed.Config Caching:
php artisan config:clear
InstallCommand for user convenience.Migration Conflicts:
create_your_package_table). Duplicate names (excluding timestamps) may now cause fewer issues.Schema::table() for updates to avoid conflicts.Package Naming:
configurePackage()->name() must match your package’s namespace (e.g., YourPackage\YourPackageServiceProvider → your-package).vendor:publish tags.Check Published Assets:
php artisan vendor:publish --dry-run --tag="your-package"
Command Debugging:
->withNameInput('name') to commands for proper argument parsing:
$package->hasCommand(YourCommand::class)->withNameInput('name');
Config Loading:
dd(config('your-package'));
Package Discovery:
dd(Package::discovered());
Migration Conflicts:
# Example: Check for conflicts without timestamps
ls database/migrations/ | grep "your_package"
Custom Publish Tags:
PackageServiceProvider to add custom tags:
public function boot()
{
$this->publishes([
__DIR__.'/../resources/lang/en/json.php' => resource_path('lang/en/json.php'),
], 'json-translations');
}
Dynamic Config:
Package::discoverFor() to load config dynamically in runtime:
$config = Package::discoverFor('your-package')->getConfig();
Conditional Publishing:
boot() to publish assets based on environment:
public function boot()
{
if (app()->environment('local')) {
$this->publishes([...], 'local-assets');
}
}
Artisan Commands:
configurePackage():
$package->hasCommand(YourCustomCommand::class);
Package Events:
PackageDiscovered events for runtime hooks:
event(new PackageDiscovered('your-package'));
How can I help you explore Laravel packages today?