internachi/modularize
Traits for Laravel package authors to add internachi/modular support to their artisan commands. The Modularize trait resolves a --module option on any command, while ModularizeGeneratorCommand routes generated files into the module directory with correct namespacing.
--module parsing, path resolution and namespacing ourselves, per command" work with a two-trait convention. The buy decision is cheap (one Composer line, MIT), but the real decision it informs is standardize the CLI contract once versus let each package invent its own --module semantics.internachi/modular? Adopting this is a soft commitment to that ecosystem as our module runtime. It's the right lever if modularization is already on the roadmap; it's a distraction if we're only experimenting with module boundaries.--module. That's a product promise we can make to users ("any module-aware command accepts --module=<Name>"), and a compatibility contract we have to protect — the non-module path must stay byte-identical.--module for free or need repeated edits.modules/<Name>/...; internal tooling that must run the same operation app-wide or module-scoped.Adopt when all of the following hold:
--module.internachi/modular and has working module registration — without it, $this->module() resolves to null and the traits do nothing.^13), and we're prepared to re-run the command test suite on Laravel/Symfony console upgrades.Look elsewhere or skip when:
internachi/modular, not this — it's a dependency of packages that ship commands.internachi/modular (or use a different modularization approach, e.g. nwidart/laravel-modules) — the traits resolve nothing.The one-liner: A tiny, MIT-licensed adapter that gives our package's Artisan commands a consistent --module=<Name> option, so a command works identically app-wide or scoped to a module — no bespoke flag parsing, no path guessing.
For executives: It's a low-cost consistency play. Instead of each package inventing its own way to target a module, we standardize one CLI convention across our tooling. Cost is a single dependency and a small amount of per-package wiring; benefit is fewer support issues, faster onboarding, and scaffolding that lands in the right place with the right namespace. The strategic dependency is internachi/modular, so this only makes sense if modularization is already part of our direction.
For engineering: Two traits, no service provider, no config, no runtime code. Modularize adds the option and hands you a read-only ModuleConfig; ModularizeGeneratorCommand adds the option and handles file placement for generators. The honest caveats: you must override getDefaultNamespace() (and getPath() for migrations, seeders, jobs, factories) yourself — otherwise generated classes compile with App\... imports inside a module. Null is the default, so guard $this->module() once at the top of handle() and keep the non-module path unchanged. Integration cost is one base command class plus one base generator class, then every concrete command inherits the behavior.
Risks to state plainly: Two stars, zero dependents, single-organization ownership, and a narrow API. Mitigate by pinning ^1.1, confining the trait to our base classes so a future ModuleConfig change is a one-file shim, and running a with/without --module test matrix so the default path can never regress. If the risk is unacceptable, the fallback is copying the two small trait files under MIT.
How can I help you explore Laravel packages today?