laravelangular/generators
LaravelAngular Generators offers Artisan commands that scaffold Laravel and Angular code, including models, migrations, controllers, routes, and Angular views, helping developers build full-stack CRUD features faster with consistent boilerplate.
Know what you're adopting first. laravelangular/generators is a Laravel 5-era package that adds AngularJS 1.x scaffolding commands to Artisan. It was last released in January 2016, has zero dependents, and targets a stack (Laravel ≤5.2 / AngularJS 1.x) that is end-of-life. Treat it as a legacy-repo tool: valuable if you maintain an existing Laravel 5 + AngularJS 1 app, not something to pull into a new project.
2.0.0 changed what the generators emit. The release notes are short but the impact isn't: the stubs are now EcmaScript 6 templates with "improved consistency for file extensions." That's a major-version bump on a package whose only job is emitting code, so assume the generated output differs from every file you generated with 1.x. If you're already using the package, read the diff on a single generated file before regenerating anything in bulk.
Install (legacy app only).
composer require --dev laravelangular/generators:^2.0
Installing as require-dev keeps the generator out of production deployments — the generated files are what ship, not the package. Verify the version actually resolved; the package's composer.json historically pinned Laravel 5.x / PHP 5.5–7.0, and there is no guarantee the 2.0.0 release widened those constraints (see Gotchas).
Register the provider. Because the package predates Laravel 5.5 package auto-discovery, add the service provider manually in config/app.php:
'providers' => [
// ...
LaravelAngular\Generators\GeneratorsServiceProvider::class,
],
If the package does ship a discovery block, auto-registration will work on 5.5+, but verify rather than assume.
Publish and inspect the config. This is your first stop:
php artisan vendor:publish --provider="LaravelAngular\Generators\GeneratorsServiceProvider"
Read the published config (typically config/angular.php) before generating anything. It controls the output paths and the Angular module name the generated code targets. With 2.0.0's ES6 output, the output path matters more than it used to — see the public/ trap in Gotchas.
First use case. Scaffold a single controller and read the output. This is now a mandatory step, not a formality, because 2.0.0 changed the template language:
php artisan list | grep ng:
php artisan ng:controller UsersController
Open the generated file and check four things: (1) it landed in the directory you expected, with the file extension and naming convention you expected, (2) the angular.module('...') name matches your app's bootstrap module, (3) it's ES6 — class, const/let, template literals, possibly import/export — and therefore needs your build step, and (4) DI is still annotation-safe, either the array form or a static $inject on the class. If any of those are wrong for your setup, fix the config or the stub now — every subsequent file inherits the mistake.
Feature-slice workflow. The package is most useful when you generate a coherent vertical slice per feature rather than one file at a time. A typical loop for a new "orders" screen:
php artisan ng:controller OrdersControllerphp artisan ng:service OrdersService — the $http wrapperphp artisan ng:directive orderRow — if you need a reusable row componentphp artisan ng:filter orderStatus — display formattingOrdersService callsGenerate in that order and immediately open each file to confirm the injected dependencies line up with what you actually need. On 2.x, also confirm the four files agree with each other on module system and naming — a service emitted as an ES module and a controller emitted as a global script registration is the kind of inconsistency you want to find after one file, not four.
Wire ES6 output into a real build step. With 1.x you could plausibly generate straight into public/js and let the browser load ES5 as-is. The 2.0.0 templates are ES6, which means that path is effectively closed for anything but evergreen-browser-only internal tools. Put the generator output behind Laravel Mix / Webpack / Rollup before it reaches the browser:
// webpack.mix.js
mix.js('resources/assets/js/app.js', 'public/js');
and set the generator's output path into resources/assets/js/... so generated files are picked up by the bundler instead of being served raw. Retrofitting this after you've generated twenty files into public/ is a git mv plus a rewrite of every script tag.
Check whether the templates are modules or globals. "ES6 templates" can mean two quite different things: ES6 syntax in a script-tag-global file (class UsersController { ... } angular.module('app').controller('UsersController', UsersController)), or actual ES modules with import/export. They need different build config and different file extensions. Determine this from the first generated file and standardize immediately — mixing the two in one AngularJS app produces load-order bugs that are painful to chase.
Class-based DI needs the annotation too. If 2.0.0 emits classes, the safe AngularJS 1.x pattern is a static $inject:
export default class UsersController {
static get $inject() { return ['$scope', 'UsersService']; }
constructor($scope, UsersService) { /* ... */ }
}
A class with only a constructor signature and no $inject will break under minification exactly like the old implicit-annotation function form did. Verify per file; don't assume the template got it right.
Pair generators with Laravel's API surface. The generated service is a $http client stub. Wire it to a real endpoint in the same sitting:
// routes/api.php (or routes.php on 5.2)
Route::get('/orders', 'OrderController@index');
Then in the generated service, replace the placeholder URL with /api/orders. Generating a service and never pointing it at a route is the most common way these stubs rot.
Subdirectory generation. Use slashes in the name to nest output, e.g. php artisan ng:controller admin/ReportsController. This keeps the controller tree aligned with your Laravel route grouping. Confirm the generator creates intermediate directories — older versions of these packages sometimes fail silently on deep paths.
Use it as a consistency enforcer, not a typing shortcut. The real value is that every controller/service in the codebase has identical boilerplate: same wrapper, same naming, same DI annotation style, same module registration. If you're reviewing a PR that hand-wrote a controller, that's the signal to regenerate. Consistency in AngularJS 1.x DI annotations is what prevents "unknown provider" errors after minification.
Laravel 5.5+ mixed stacks. If you're incrementally migrating a Laravel 5 app off AngularJS, keep using the generators for untouched modules and stop using them for new work. The 2.0.0 ES6 switch makes this boundary sharper: ES6 output in a module you're actively converting to Vue/React will collide with your new build conventions. Generate only into the legacy side of the line.
The 2.0.0 upgrade is a breaking change for existing repos. Two things move at once: the template language (ES5 → ES6) and file extensions/naming. Consequences you should plan for:
require, script tag, or AngularJS files array that references the old extension breaks silently and shows up as a missing-module error in the browser, not PHP.^1.0 won't pick this up; anything on ^2.0 will. Confirm what your composer.lock actually resolved to before you blame the wrong version for a weird stub.ES6 output means ES6 browser and tooling requirements. No IE11, no raw <script> inclusion on older Safari, and no serving unstranspiled files from public/js unless your audience is modern-browser-only. Also check your minifier: if it's an old uglify-js 2.x, it will choke on ES6 syntax. Move to terser or equivalent as part of the upgrade, not after the first failed build.
Composer will fight you. The package's composer.json historically pins Laravel 5.x and PHP 5.5–7.0 constraints, and the 2.0.0 notes don't mention widening them — verify before assuming. On a modern Laravel you'll hit a dependency resolution wall. Options, in order of preference:
app/Console/Commands and drop the dependency.composer require --dev ... --ignore-platform-reqs (works, but you're now on your own for runtime incompatibilities).The module name is hardcoded in the generated output. If your Angular app bootstraps as myApp but the generator emits angular.module('app'), every generated file will silently fail to register. This doesn't throw a PHP error — it fails at runtime in the browser with an unhelpful $injector:nomod. Check the config's module key first, and grep the first generated file for angular.module before generating twenty more.
Output path defaults to public/, not resources/assets/. This was a nuisance in 1.x; with ES6 templates it's a functional blocker. Files served directly from public/js never pass through your build pipeline — no transpilation, no minification, no cache busting — and ES6 output served untranspiled will simply fail on your target browsers. Set the path into resources/assets/js in the config before the first generation, or you'll be moving files indefinitely.
Minification-safe DI is still the thing to verify. Open a generated controller and confirm the annotation is present and correct in whatever form 2.0.0 emits. If the template dropped it in the ES6 rewrite, you'll get $injector:unpr errors only in the production build, which is the worst possible time to find out. Add a smoke test that loads the minified bundle.
Debugging generated-code problems. Work in this order: php artisan list | grep ng (are the commands registered at all?) → php artisan ng:controller --help (what options does this version actually support?) → generate one file into a scratch directory and read it → check the browser console for $injector and module-load errors rather than PHP errors, since the generators can't validate Angular semantics.
No --force guarantees. Overwriting existing files may prompt, silently skip, or clobber depending on version. Commit before bulk-generating so you can git diff and git checkout what you didn't mean to change. On a major version bump this is doubly important — a stray ng: invocation can rewrite a whole directory into a new syntax style.
Extension point: publish stubs first, subclass second. The cleanest customization path is to publish the stubs (if 2.0.0 exposes them via vendor:publish) and edit them, so your team's conventions — strict DI, controllerAs, a vm alias, your preferred module system — live in your repo. If stubs aren't publishable, extend the package's command classes and override the stub/template method in app/Console/Commands. Either way, pin the package version once you've forked the templates; a future template change will otherwise silently diverge from your edits.
Don't expect maintenance. One 2016 release plus a single 2.0.0 template refresh is not maintenance — the Laravel 5 / PHP 5.5–7.0 constraints and the AngularJS 1.x target are unchanged, and there will be no fixes for PHP 7.4+/8.x deprecations. Budget for the package to become a liability; the migration path remains "inline the three or four command classes you actually use," and 2.0.0 is the natural moment to do it, since you're already reviewing the generated output.
How can I help you explore Laravel packages today?