nyoncode/wire-core
Core foundations for the nyoncode/wire package family, offering shared utilities, helpers, and base abstractions that simplify building Laravel and Livewire applications while keeping wire-powered projects consistent.
There is no README, no docs site, no example app, and zero dependents. Your first hour is orientation, not building — plan accordingly.
Install, pinned.
composer require nyoncode/wire-core
Before you run anything else, open vendor/nyoncode/wire-core/composer.json and check two things: the require block (does it declare laravel/framework and php constraints, or does it float?) and whether the install resolved to a tag or dev-main. If it's dev-main only, treat the package as a reference implementation and copy the code you need into app/ under MIT rather than depending on it. Commit composer.lock either way.
Verify boot, then read top-down. Confirm the service provider is auto-discovered via extra.laravel.providers, then run php artisan about and check for new bindings. Publish anything publishable (php artisan vendor:publish --provider=...) so config and views land in your project where you can read and diff them — never operate against vendor config you can't see. After that, read in this order:
src/ service provider — this is the real API surface (bindings, singletons, Blade namespaces), not the traits.The first use case: one throwaway Livewire screen. Pick an internal settings page — not checkout, not anything on the critical path. Put a modal-driven form on it with a success notification. That single screen touches modal state, notification dispatch, color tokens, and view conventions at once, and it will tell you within an afternoon whether the abstraction earns its keep or is decorative.
Build the wrapper before you build the feature.
namespace App\Livewire;
use NyonCode\WireCore\...\BaseComponent; // verify the real FQCN from src/
abstract class WireComponent extends BaseComponent
{
// app-wide trait composition, defaults, and overrides live here
}
Every component you write extends App\Livewire\WireComponent. Compose the package's traits on this wrapper, never on individual components. If you ever fork or rip the package out, the blast radius is one file plus your use statements.
Trait composition on the wrapper, not per component. The package's value proposition is traits you mix in. Mixing them in twenty components means twenty places to audit when an upstream signature changes and twenty chances at a method collision. Mix them into App\Livewire\WireComponent once. If a specific component genuinely needs a narrower surface, extend an intermediate abstract class rather than pulling traits in ad hoc.
Invokable actions for every user-triggerable operation. This is the cleanest idea in the bundle: one small invokable class per operation (archive, resend, approve) with an explicit entry point and an explicit return type. Your Livewire component should call the action, catch one known exception type, and render the outcome in one place. Business logic stays out of the component. The payoff — uniform error handling, uniform authorization, testable in isolation — is real, and you can replicate the shape even if you stop using the package tomorrow.
Modal state as properties, payload as an ID. Hold open/closed state and the record identifier in component properties, drive the Blade modal off them, and reset on close. The rule to insist on: modals receive an ID, never a serialized model. The action they dispatch re-fetches the record. Livewire rehydration makes stale serialized models the single most common modal bug in the ecosystem, and no foundation package can fix that for you — it's a discipline, not a feature.
Dispatch notifications at the edge, not inside actions. Let the action return a result object; let the component translate that result into a flash or notification. If notifications are dispatched inside actions, the actions become untestable in isolation and unusable from a queue job or artisan command. If the package's notification surface doesn't feel like a thin adapter over that pattern, drop it and use session()->flash().
Treat icons and colors as design tokens you happen to have borrowed. Two rules: resolve icons through one helper (never inline <svg> across twenty views), and reference colors semantically (success, warning, danger) rather than by palette index so a token change is a single map edit. Wrap the bundled icon registry in your own App\Support\Icon facade on day one — icon sets churn faster than anything else in a UI layer, and a Heroicons-to-Lucide swap should be one file.
Follow view conventions wholly or not at all. A half-followed Blade naming convention costs more than no convention. Where the package's component namespace collides with an in-house convention, your wrapper wins — write the override down.
Build a regression net immediately. Add tests/Feature/Wire/ with two or three feature tests per subsystem you actually use. There is no upstream CI to catch breakage; your tests are the entire safety net, and they're what makes a composer update a five-minute task instead of a bisect.
Wire up visibility. Add a Renovate/Dependabot entry for the package so upstream commits show up as PRs rather than as surprises at deploy time.
Trait method collisions are boot-time fatals, and they're the top risk. Laravel fatals on duplicate trait methods, and the error names the class, not the two traits at fault — bisecting a whitescreen is expensive. Before mixing any package trait into an existing base class, diff method lists:
php -r 'require "vendor/autoload.php";
$r = new ReflectionClass("NyonCode\\WireCore\\...\\SomeTrait");
foreach ($r->getMethods() as $m) echo $m->getName(), "\n";' > /tmp/wire.txt
Fifteen minutes now versus an afternoon later.
No tagged releases is a hard stop for production use. You cannot meaningfully constrain dev-main. If there are no semver tags: pin to a commit hash, lock the file, and treat it as frozen. Or vendor the source you use under MIT and drop the dependency. A foundation-tier dependency with a bus factor of one and zero dependents is not something to put on a critical path.
An unconstrained laravel/framework requirement means you're the CI. If the package doesn't pin a framework range, every Laravel minor upgrade you do is an untested integration against it. Check the require block on day one, not on the day it breaks.
Undocumented container bindings are hidden coupling. The service provider is the actual API — anything it binds as a singleton or binds against an interface is a place where upstream change surfaces as a runtime error in an unrelated request path. Prefer constructor injection over app() lookups so failures land loudly and locally.
The source is the spec. Any behavior you rely on that isn't covered by a test you own can change without notice. Two or three feature tests per subsystem is adequate and cheap.
Keep the fork cheap by design. Pre-agree a trigger — "no tagged release in 180 days" is reasonable — and keep App\Livewire\WireComponent and App\Support\Icon thin. The moment service providers and published config become load-bearing, fork cost jumps from an afternoon to a week. Keep them non-load-bearing deliberately.
Don't retrofit onto an existing app. If you already have in-house actions, a notification contract, or an icon strategy, adopting this gives you duplicate trait methods, competing notification contracts, and two icon-resolution paths. The convenience delta never covers the migration. Greenfield surface, or pattern-reference only.
The highest-value use today is reading it. MIT-licensed traits and action classes are a free reference implementation of a small primitives layer. If your portfolio has three Laravel apps hand-rolling the same modal and action patterns, read this, take the three or four ideas worth keeping, and write your own — your version will have tests, releases, and an owner.
Extension points to prefer, in order: your wrapper base class, your Icon facade, your action result types, your config overrides. Every one of those keeps upstream at arm's length while preserving the ergonomics that made you look at this in the first place.
How can I help you explore Laravel packages today?