Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Modular Livewire Laravel Package

internachi/modular-livewire

A Livewire plugin for internachi/modular that automatically discovers Livewire components in each module's src/Livewire directory and registers them as module::component names. Components are kebab-cased, subdirectories use dot notation, and they're instantly usable in Blade.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install, resolve the version matrix. The README claims Laravel 11+, but the 2.0.0 release notes explicitly say Laravel 11 support was dropped — and Livewire 4 support only landed in 1.1.0. Read composer.json on the tag you intend to use instead of trusting the README, then pin explicitly ("internachi/modular-livewire": "2.0.1" rather than ^2.0) so an upstream major drop doesn't land mid-sprint. You also need internachi/modular ^3.0 already in place — this package is a plugin for it and does nothing on its own.

composer require internachi/modular-livewire

Nothing to publish, no config file, no assets. The service provider and the modular plugin are picked up by package discovery.

Where to look first. Don't read the docs twice — read the package source (it's roughly a service provider plus a plugin) to confirm the exact scanning rules: which directory, whether directory names are kebab-cased as well as class names, and whether non-concrete classes are filtered. Those three details determine everything else you'll do day to day. Then look at one existing module's src/Livewire/ to see the convention in practice.

First use case — the migration of exactly one component. Take a component currently registered with Livewire::component('invoice-table', ...) in AppServiceProvider:

  1. Move the class to app-modules/billing/src/Livewire/InvoiceTable.php (namespace per the module's PSR-4 root).
  2. Delete the manual registration line.
  3. Change <livewire:invoice-table /> to <livewire:billing::invoice-table />.
  4. Hit the page, run the test suite, and confirm the component renders and hydrates.

That's the whole loop. The value proposition is that step 2 never happens again — the next component a teammate adds to that folder is registered by virtue of existing. Verify the alias resolves before moving on: Livewire::getClass('billing::invoice-table') in tinker, or a throwaway Livewire::test('billing::invoice-table').

Implementation Patterns

Alias derivation. The mapping is mechanical, and you should be able to predict it without running the app:

File Alias
billing/src/Livewire/InvoiceTable.php billing::invoice-table
billing/src/Livewire/Reports/MonthlySummary.php billing::reports.monthly-summary
users/src/Livewire/UserProfile.php users::user-profile

Class name → kebab-case; subdirectories → dot notation; module directory name → prefix. Write that table into your module's README so new hires don't guess.

Four ways to reference a component, and when to use each.

  • <livewire:billing::invoice-table /> — the default in Blade. Prefixed, collision-free, and the module origin is visible at the call site.
  • @livewire('billing::invoice-table') — same thing when you need to pass it around or inside a directive.
  • @livewire(\AppModules\Billing\Livewire\InvoiceTable::class) — class-based. Use this during refactors and in tests: it survives alias changes, so it isolates "did the component break?" from "did the alias break?".
  • Full-page routes: Route::get('/billing/invoices', InvoiceTable::class) works normally; the alias isn't involved in routing.

Always define render() explicitly with a module-scoped view namespace (e.g. return view('billing::livewire.invoice-table');). Livewire's convention-based view guessing is anchored to App\Livewire\...; across arbitrary module namespaces it's not a safe assumption. Being explicit costs one line and removes a whole class of "view not found" surprises.

Coexistence, not cutover. Discovered components and manual Livewire::component() calls run side by side. That lets you migrate module by module while both mechanisms are live. The only change with real blast radius is the Blade rename — grep for livewire: and @livewire( and review the diff, don't eyeball it.

Testing. Test the component by class (Livewire::test(InvoiceTable::class)) so failures point at your code, and add one cheap smoke test per module that renders the alias (Livewire::test('billing::invoice-table')->assertOk()) so a bad rename or path move fails CI rather than production. assertSeeLivewire('billing::invoice-table') in a feature test covers the Blade side.

Boundary discipline. Components belong in the module that owns the domain, and other modules consume them through the alias — never by reaching into another module's Livewire namespace directly. The prefix makes violations obvious in review, which is a real day-to-day benefit of the convention.

New module checklist. Create src/Livewire/, confirm the module's PSR-4 root is registered (composer dump-autoload if the namespace is new), drop the component in, use the prefixed alias. No provider edits anywhere.

Gotchas and Tips

The convention is not configurable — this is the ceiling, not a bug. Fixed path, fixed alias scheme, no per-component custom alias, no dynamic/runtime registration, no config file to publish. If a requirement needs a bespoke alias or a non-standard directory, the answer is a fork or a manual Livewire::component() layered on top, not a config flag. Decide that before you build on it.

Renaming anything is a breaking change. Renaming a class changes the alias; renaming a module directory changes every alias in that module. Both fail silently at boot and noisily at render ("component not found"). Treat module directory names and component class names as public API: grep for {module}:: before you rename, and let the smoke tests catch the rest.

Keep only concrete components in src/Livewire/. Abstract base classes, traits, interfaces, and supporting DTOs placed there risk being registered as components. Whether the scanner filters them is worth confirming in source — until then, put shared base classes in src/Livewire/Concerns/ or, better, src/Support/. A boot-time failure from an abstract class is an unpleasant way to learn this.

Watch boot cost if you have many modules. Discovery is a directory scan per module; whether it runs once or per request depends on how the plugin integrates with modular's boot cycle. Profile a cold request before and after on a realistic module count. If it shows up, that's your argument for caching the map — and it's also the point where you'd fork.

Support posture is a design constraint, not a footnote. One maintainer, two stars, zero dependents, a changelog dominated by Dependabot bumps, and breaking releases whose only content is dropping a Laravel major. There is no vendor and no triage. Pin the version, name a human owner for the dependency, and keep the in-house alternative (a ~50-line service provider implementing the same convention) on the table — it's genuinely competitive if you only need the discovery loop.

Debugging checklist when an alias 404s. Confirm file path under src/Livewire/; confirm class name matches filename; check casing (kebab-casing of InvoiceTable vs Invoicetable); composer dump-autoload after adding a class or module; clear compiled views if the Blade tag changed; and Livewire::getClass('billing::invoice-table') to see whether the registry or your string is wrong.

Use the class name in error paths. When something breaks, temporarily switching a Blade tag to the class-based form tells you instantly whether the problem is discovery/aliasing or the component itself. It's the fastest bisect available with a package that has no debug tooling.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings