nyoncode/laravel-package-toolkit
Toolkit for building Laravel packages with less boilerplate: configure routes, migrations, translations, views/components, middleware, assets and commands. Includes install/about commands, publishing options, lifecycle hooks, and package-specific exception handling.
composer require nyoncode/laravel-package-toolkit
PackageServiceProvider and implementing Packable:
use NyonCode\LaravelPackageToolkit\PackageServiceProvider;
use NyonCode\LaravelPackageToolkit\Packager;
class MyPackageServiceProvider extends PackageServiceProvider
{
public function configure(Packager $packager): void
{
$packager
->name('My Package')
->hasConfig()
->hasRoutes();
}
}
config/app.php under providers.php artisan vendor:publish --provider="MyPackageServiceProvider"
Add a route and config:
$packager
->name('My Package')
->hasConfig(['config.php'])
->hasRoutes(['web.php']);
config.php in config/ and web.php in routes/.config('my-package.key').Use when() for environment-specific resources:
$packager
->hasRoutes()
->whenLocal(function ($packager) {
$packager->hasConfig('local-config.php');
})
->whenProduction(function ($packager) {
$packager->hasConfig('production-config.php');
});
Leverage hooks for initialization logic:
$packager
->registeringPackage(function () {
Log::info('Package is registering...');
})
->bootedPackage(function () {
Event::listen('my-event', MyListener::class);
});
Register middleware dynamically:
$packager
->whenEnvironment(['local'], function ($packager) {
$packager->hasMiddlewareGlobals([DebugMiddleware::class]);
});
Register components with namespaces:
$packager->hasComponents([
'admin' => [
'dashboard' => DashboardComponent::class,
],
]);
Use in Blade:
<x-my-package::admin.dashboard />
Pass data to all views:
$packager->hasViews(sharedData: [
'version' => '1.0.0',
]);
Extend the InstallCommand:
use NyonCode\LaravelPackageToolkit\Commands\InstallCommand;
class MyInstallCommand extends InstallCommand
{
protected $signature = 'my-package:install {--force}';
protected $description = 'Install My Package';
public function handle(): void
{
$this->call('vendor:publish', ['--provider' => 'MyPackageServiceProvider']);
$this->info('Package installed!');
}
}
Register in configure():
$packager->hasCommands([MyInstallCommand::class]);
Migration Timestamps:
canLoadMigrations() to load unpublished migrations directly (but test thoroughly).Route Conflicts:
Route::prefix('my-package')->group(function () {
// Routes here
});
Conditional Logic Overhead:
when() can bloat the configure() method. Group related conditions:
$packager->when(fn () => $this->app->environment('local'), function ($packager) {
$packager->hasConfig('local-config.php')->hasCommands();
});
View Publishing:
viewsPath declared in hasViews(). Use absolute paths if needed:
$packager->hasViews(directory: __DIR__.'/../../resources/views/my-package');
Middleware Priority:
hasMiddlewareGroups() for earlier execution in specific groups.Check Published Files:
php artisan vendor:publish --tag=config --provider="MyPackageServiceProvider" --force
Verify files appear in config/ or resources/views/.
Lifecycle Hooks: Add debug logs to hooks to trace execution order:
->registeringPackage(function () {
Log::debug('Registering package...');
});
Route Debugging:
Use php artisan route:list to verify package routes are loaded. Filter by namespace:
php artisan route:list | grep "my-package"
Custom Packager:
Extend Packager to add methods:
class CustomPackager extends Packager
{
public function hasWebhooks(): static
{
return $this->addResource('webhooks', WebhookService::class);
}
}
Dynamic Resource Loading: Load resources based on runtime checks:
$packager->when(fn () => file_exists($this->app->basePath('custom-file')), function ($packager) {
$packager->hasConfig('custom-file');
});
Override Default Directories: Use absolute paths for non-standard layouts:
$packager->hasViews(directory: __DIR__.'/../../custom-views');
Avoid hasCommands() in Production:
Commands add overhead. Use whenProduction() to exclude them:
$packager->whenLocal(function ($packager) {
$packager->hasCommands();
});
Lazy-Load Heavy Resources: Defer migrations or translations until needed:
$packager->hasMigrations()->canLoadMigrations(false);
Mock the Packager:
In tests, mock the Packager to verify configuration:
$packager = $this->createMock(Packager::class);
$provider = new MyPackageServiceProvider($this->app);
$provider->configure($packager);
$this->assertEquals('My Package', $packager->name());
Test Conditional Logic: Override environment checks:
$this->app->shouldReceive('environment')->andReturn('local');
How can I help you explore Laravel packages today?