amranidev/lpackager
Lpackager is a Laravel package scaffolding tool that generates boilerplate and structure for reusable packages, helping you set up service providers, configuration, routes, and resources faster. It gives you a starting point for building and distributing Laravel packages with less manual setup.
amranidev/lpackager is a workbench-style scaffolding generator: it writes a Laravel package skeleton into a packages/ directory at the root of your app so you can develop a package in-place, then extract it later. It is not a runtime dependency — treat it as a dev tool.
1. Install (dev-only):
composer require --dev amranidev/lpackager
On Laravel 5.5+ the service provider is auto-discovered. On older versions add Amranidev\Lpackager\LpackagerServiceProvider::class to config/app.php.
2. Look here first:
php artisan list — filter for the package's commands (they are prefixed packager: in most versions). Confirm the exact signatures your installed version exposes before scripting anything; the CLI surface changed across releases and the README on GitHub tracks master, not necessarily the 2018-11-04 tag you'd get from Composer.config/lpackager.php (publish with php artisan vendor:publish if it isn't there) — controls where packages are generated and the default namespace/vendor used by the prompt defaults.packages/<vendor>/<name>/{src,composer.json,README.md}. Read the generated composer.json and service provider before writing code — that's the contract everything else hangs off.3. First use case. The fastest way to see the value is to pull one self-contained slice out of an app — a "Blog" module with a model, migration, routes, and views:
php artisan packager:new Acme Blog
You'll be prompted for vendor, package name, author, and description. Then wire the new namespace into the root autoloader:
"autoload": {
"psr-4": {
"Acme\\Blog\\": "packages/acme/blog/src"
}
}
composer dump-autoload
If the skeleton's composer.json does not include extra.laravel.providers, register the generated BlogServiceProvider manually in config/app.php — don't assume auto-discovery applies to a package that lives in packages/ rather than vendor/.
Scaffold → iterate → extract. The intended loop is: generate into packages/, build and test the feature there while the host app uses it via the PSR-4 mapping, then either keep it as a path dependency or move it to its own repo and composer require it for real. Keep the packages/ tree in the app's git history while iterating; only .gitignore it once the package is published and pinned by version.
Path repository for proper dependency semantics. Once the package has its own composer.json, prefer a path repo over hand-edited PSR-4 so the package's own require block actually resolves:
"repositories": [{ "type": "path", "url": "packages/acme/blog" }],
"require": { "acme/blog": "*" }
This catches namespace and autoload mistakes early, because Composer validates them instead of relying on your root mapping.
Let the generator own the boilerplate, you own the wiring. Generated providers typically register config, routes, migrations, and views with the usual loadViewsFrom/loadMigrationsFrom/mergeConfigFrom calls and a __DIR__.'/../routes/web.php' path. Verify each of those paths points where you think it does after any rename, and keep routes namespaced (Route::namespace('Acme\Blog\Http\Controllers')->group(...)) so package routes don't collide with app routes.
Use the migrate helper for iteration speed. Running package migrations straight from the tool (packager:migrate, vendor/package arguments) avoids the copy-into-database/migrations dance during development. The moment you're happy with the schema, switch to loadMigrationsFrom in the provider and let the host app's php artisan migrate handle it — that's the behaviour you want in downstream installs.
Duplicate for multi-tenant or variant packages. When you need a second package that's 90% the same (e.g. Blog and News), generate from an existing skeleton rather than from scratch, then do a global find-and-replace on namespace and on any hardcoded package name strings. Do this before writing feature code; renaming after the fact is where most time is lost.
Test the generated package in isolation. Add orchestra/testbench to the generated package and run its own PHPUnit suite there. A package that only works when mounted in the host app isn't ready to be extracted — the whole point of the tool is portability.
str_slug removal, and provider auto-discovery nuances. Pin your Laravel version or budget time to patch the generator. For new projects, weigh laravel-packager or Laravel's own php artisan package-workbench patterns as alternatives.composer dump-autoload is the #1 "class not found" cause. Every generate, rename, or namespace change needs it. If a class still won't resolve, check the generated composer.json psr-4 key against the actual directory casing — PSR-4 is case-sensitive on Linux and silently forgiving on macOS, so it'll break in CI only.$namespace, route controller strings, view namespace in loadViewsFrom, migration class names). After any duplication, grep -ri "<oldname>" packages/ and fix by hand.config/lpackager.php and edit the published copy — changes inside vendor/amranidev/lpackager disappear on the next composer update.view('package::path') from the host app. If your views render blank, that's usually a missing double-colon or a loadViewsFrom path one directory off.psr-4 mapping and the packages/ entry in the same commit, then composer dump-autoload -o. Leaving both in place gives you two copies of the same class and a confusing "which one is loaded" bug.How can I help you explore Laravel packages today?