liberusoftware/developer-experience-livewire
A Livewire developer-experience package from Liberu Software that bundles practical tooling and utilities for Laravel Livewire projects, helping you scaffold, debug, and maintain interactive components with less boilerplate and a smoother day-to-day workflow. Built for Liberu's modular Laravel stack...
This is a presentation adapter: it is expected to contain Livewire components, views and view-models that sit on top of the domain package liberusoftware/module-developer-experience. Treat it as UI-only and expect the actual behaviour (services, DTOs, policies, migrations) to live in the domain module — install both, not just this one.
Minimal steps:
composer require liberusoftware/developer-experience-livewire
Read composer.json first, not the README. With no docs to speak of, the require block tells you the real contract: minimum PHP/Laravel, whether it expects livewire/livewire:^3.0, and whether the domain module is a hard or suggested dependency. Then read extra.laravel.providers — if the service provider is not listed there for auto-discovery, you must register it yourself in bootstrap/providers.php (Laravel 11+) or config/app.php.
Confirm the component aliases. Grep the provider for Livewire::component( and loadViewsFrom(:
grep -rn "Livewire::component\|loadViewsFrom\|loadRoutesFrom\|mergeConfigFrom" vendor/liberusoftware/developer-experience-livewire/src
That one command gives you the alias names, the Blade namespace (probably developer-experience-livewire:: or similar), and whether config/views/routes are publishable.
Publish what exists, then check what changed:
php artisan vendor:publish --provider="Liberu\DeveloperExperience\Livewire\...ServiceProvider"
Publishing views to resources/views/vendor/... is usually the fastest way to learn the component structure without reading every class.
Mount the first component in a plain Blade view — not in your app layout — so you can rule out CSS/JS conflicts separately from component bugs:
<livewire:developer-experience::some-component />
First use case: wire a single read-only panel (a status/summary/list view) into an existing dashboard page. Read-only components exercise all the failure points — component resolution, view namespace, asset pipeline, authorization — without any write-path risk. Get that rendering, then add actions.
Where to look first, in order: src/Livewire/ (the public API surface) → the service provider (registration + namespaces) → resources/views/livewire/ (props actually consumed) → tests/ if present. The tests are the only reliable documentation of intended usage for a package at this maturity.
Keep components thin, keep logic in the domain module. The value of an adapter package is that it is disposable. If you need behaviour the component doesn't expose, add a method to the domain service and call it from a subclassed component — do not put business rules in the Livewire class, or you'll be re-implementing them when the package changes shape.
Subclass rather than fork when you need to change behaviour:
namespace App\Livewire;
use Liberu\DeveloperExperience\Livewire\Components\SomeComponent as BaseComponent;
class SomeComponent extends BaseComponent
{
public function mount(): void
{
parent::mount();
$this->authorize('viewAny', SomeModel::class);
}
}
Then re-register the alias in your own provider after the package provider runs (Livewire::component('developer-experience::some-component', SomeComponent::class)). This survives composer update; a published-view hack does not survive view structure changes.
Composition over configuration for layouts. Adapter packages usually ship a layout or assume one. Don't adopt theirs — instead render into your app's layout and let components use their own views:
{{-- resources/views/dashboard.blade.php --}}
<x-app-layout>
@livewire('developer-experience::summary')
</x-app-layout>
This avoids the classic double-inclusion of Livewire's @livewireStyles / @livewireScripts and sidesteps any Tailwind/asset conflicts.
Cross-component communication via events, not shared state. If the package ships multiple components that need to stay in sync, have them talk through domain events or Livewire dispatch:
$this->dispatch('developer-experience-refreshed')->to(OtherComponent::class);
#[On('developer-experience-refreshed')]
public function refresh(): void { $this->reset('items'); }
Note the version split: emit()/$listeners is Livewire 2, dispatch()/#[On] is Livewire 3. If the package reads as Livewire 3 in composer.json but you see emit() in the source, it was written for v2 and only half-ported — check before building on the event layer.
Isolate write paths behind your own actions. For anything that creates or mutates data, wrap the component in a page you control so validation, authorization and audit logging happen in your code:
Livewire::test(SomeComponent::class)
->set('name', 'x')
->call('save')
->assertHasNoErrors()
->assertDispatched('saved');
Integration tip — policies before components. In a multi-tenant/modular stack like Liberu's, the domain module typically owns the Eloquent models and policies. Wire AuthorizesRequests and the policies in your app first, then mount components; retrofitting authorization into a working dashboard is how tenant leaks happen. If the package components call Model::query() internally without an authorize() call, wrap or subclass them rather than trusting the view layer.
Testing pattern that pays off: pin your test suite to the component aliases, not the classes. Livewire::test('developer-experience::summary') keeps passing when the package renames classes, and it fails loudly when it renames aliases — which is exactly the signal you want.
NOASSERTION. This is the single biggest risk here. It means the repo has no machine-readable license, which in practice means no clear grant of rights. Read LICENSE/composer.json license field before shipping anything commercial, and get a written answer if it's ambiguous. For internal tooling it's usually tolerable; for distributed products it may not be."liberusoftware/developer-experience-livewire": "1.2.3", not ^1.0) and commit composer.lock. Better still, mirror it into a path or VCS repository you control so an upstream force-push or deletion can't break your build.composer show -a liberusoftware/developer-experience-livewire and check whether you're getting a real tag or dev-main. If it's dev-main, pin the commit hash.<livewire:...> throws, check bootstrap/providers.php first, then php artisan config:clear (a cached config from before install will hide newly merged package config).mergeConfigFrom only runs at container boot. After editing published config or upgrading, always php artisan optimize:clear. Conversely, remember config:cache in production will freeze merged values.content array in tailwind.config.js (or @source in Tailwind 4), and confirm the built CSS changed.@livewireStyles/@livewireScripts.resources/views/vendor/ with similar names is common in module ecosystems. Always use the namespaced form developer-experience-livewire::... rather than bare view names.php artisan optimize:clear plus whatever module cache command your skeleton uses), then re-run composer dump-autoload.dd() inside render() is unreliable under Livewire's request cycle. Instead use Livewire::test(...)->html() in tinker/tests, check storage/logs/laravel.log for the swallowed exception, and set APP_DEBUG=true locally — Livewire surfaces render exceptions as 500s that look like blank components when debug is off.vendor/. Only (1) and occasionally (2) survive an upgrade. If you find yourself at (4), stop and copy the component into app/Livewire/ instead — at this package's maturity, that's a legitimate and often correct decision.How can I help you explore Laravel packages today?