Installation
composer require --dev jeroen-g/laravel-packager
Run the publisher to set up config (if needed):
php artisan vendor:publish --provider="JeroenG\LaravelPackager\PackagerServiceProvider"
First Use Case: Scaffold a New Package
php artisan package:make MyPackage
This generates a boilerplate package structure in packages/MyPackage/ with:
composer.jsonsrc/ (core logic)tests/ (PHPUnit)config/ (publishable config)resources/ (views, lang, etc.)README.mdKey Files to Review First
packages/MyPackage/composer.json: Define package metadata, autoloading, and Laravel-specific keys like extra.laravel.packages/MyPackage/src/MyPackageServiceProvider.php: Register package services, bindings, and migrations.packages/MyPackage/config/package.php: Default config (published via php artisan vendor:publish).composer require ./packages/MyPackage to link the package in your Laravel app.
composer require ./packages/MyPackage --dev
php artisan test --filter=MyPackageTest
php artisan vendor:publish --provider="MyPackage\MyPackageServiceProvider" --tag="config"
php artisan vendor:publish --provider="MyPackage\MyPackageServiceProvider" --tag="migrations"
MyPackageServiceProvider to bind facades, commands, or events:
public function boot()
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'my-package');
$this->publishes([__DIR__.'/../config/package.php' => config_path('package.php')], 'config');
}
php artisan package:make-command MyCommand --package=MyPackage
Register it in MyPackageServiceProvider:
$this->commands([MyCommand::class]);
composer.json (e.g., "version": "1.0.0").
Tag releases with:
git tag v1.0.0
git push origin v1.0.0
composer.json has:
"require": {
"php": "^8.0",
"laravel/framework": "^9.0"
},
"extra": {
"laravel": {
"providers": ["MyPackage\\MyPackageServiceProvider"]
}
}
Submit to Packagist manually or via GitHub Actions.Use Laravel’s config system to make settings dynamic:
// In MyPackageServiceProvider::boot()
config(['package.default_setting' => env('PACKAGE_DEFAULT_SETTING', 'default')]);
Publish the config file and override via .env:
PACKAGE_DEFAULT_SETTING=custom_value
For Laravel 5.5+, ensure composer.json includes:
"extra": {
"laravel": {
"discover": true
}
}
This auto-loads the service provider without manual registration.
Use Laravel’s testing helpers in tests/Feature/:
public function test_package_functionality()
{
$response = $this->get('/my-package/endpoint');
$response->assertStatus(200);
}
Mock dependencies with Laravel’s Mockery or createMock().
For frontend assets (e.g., JavaScript/CSS), use Laravel Mix or Vite:
// resources/js/package.js
window.MyPackage = { /* ... */ };
Compile with:
npm run dev
Publish assets via publishes in the service provider:
$this->publishes([
__DIR__.'/../resources/js/dist/package.js' => public_path('vendor/my-package/package.js'),
], 'assets');
composer dump-autoload.composer.json has correct autoload paths:
"autoload": {
"psr-4": {
"MyPackage\\": "src/"
}
}
Run:
composer dump-autoload
config/app.php under providers.
For Laravel 5.5+, ensure "discover": true is set in extra.laravel.php artisan config:clear
Or manually merge config in MyPackageServiceProvider::boot():
$this->mergeConfigFrom(__DIR__.'/../config/package.php', 'package');
Vendor\PackageName\...) and avoid App or Laravel prefixes..env.testing is configured for CI:
APP_ENV=testing
DB_CONNECTION=sqlite_memory
Use php artisan test --env=testing to debug.Add debug logs in MyPackageServiceProvider:
public function boot()
{
\Log::info('MyPackage initialized');
}
Check logs with:
tail -f storage/logs/laravel.log
Inspect bindings:
\Log::info('Container bindings:', [
'my_package_binding' => app()->bound('my.package.binding') ? app('my.package.binding') : 'Not bound'
]);
Ensure composer.json scripts run correctly:
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover"
]
}
Extend the package’s CLI with:
php artisan package:make-command MyCustomCommand --package=MyPackage
Example: Add a package:generate-key command for API tokens.
Use Laravel’s PackageDiscovery to load packages conditionally:
// In a custom service provider
if ($this->app->environment('local')) {
$this->loadPackage('MyPackage\\LocalPackageServiceProvider');
}
Define dependencies in composer.json:
"require": {
"laravel/framework": "^9.0",
"spatie/laravel-package-tools": "^1.0" // Example dependency
}
Listen to Laravel events in MyPackageServiceProvider:
public function boot()
{
event(new \MyPackage\Events\PackageInitialized());
}
Dispatch events from package logic:
event(new \MyPackage\Events\TaskCompleted($task));
For API packages, use Laravel’s ApiResource:
namespace MyPackage\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class MyResource extends JsonResource
{
How can I help you explore Laravel packages today?