Automatic skeleton placeholders for lazy Livewire components.
Wirebones captures the real rendered layout of your Livewire components in Chromium, converts it into compact skeleton markup, and serves that markup through Livewire's lazy placeholder flow.
Instead of hand-maintaining loading states that drift from the final UI, mark a component with #[Wirebone], run a build, and let Wirebones generate production-ready placeholder Blade files.
- PHP 8.2+ with Laravel 12, or PHP 8.3+ with Laravel 13
- Laravel 12 or 13
- Livewire 4
- Node.js with Playwright Chromium installed
Install the package with Composer:
composer require mrfelipemartins/wirebonesInstall Playwright in your application:
npm install --save-dev playwright
npx playwright install chromiumPublish the configuration file when you need to customize capture or rendering behavior:
php artisan vendor:publish --tag=wirebones-configAdd the #[Wirebone] attribute to a Livewire component and point route to a page where that component is rendered:
use Livewire\Component;
use MrFelipeMartins\Wirebones\Attributes\Wirebone;
#[Wirebone(route: '/dashboard')]
class Revenue extends Component
{
public function render()
{
return view('livewire.revenue');
}
}Render the component using Livewire delayed loading:
<livewire:revenue lazy />Livewire 4 also supports deferred loading and bundled lazy requests:
<livewire:revenue defer />
<livewire:revenue lazy.bundle />Run your Laravel app, then build the skeletons:
php artisan wirebones:buildBy default, Wirebones uses config('app.url') as the base URL. You may also pass a URL explicitly:
php artisan wirebones:build http://localhost:8000use MrFelipeMartins\Wirebones\Attributes\Wirebone;
#[Wirebone(
name: 'revenue-card',
route: '/dashboard',
breakpoints: [375, 768, 1280],
wait: 800,
leafTags: ['p', 'h1', 'h2'],
excludeTags: ['svg'],
excludeSelectors: ['[data-no-wirebone]'],
captureRoundedBorders: true,
)]name: generated placeholder lookup name. Defaults to the Livewire-style component name.route: page Wirebones visits to capture the component.breakpoints: viewport widths to capture.wait: milliseconds to wait after page load before capturing.leafTags: tags captured as content bones.excludeTags: tags ignored during capture.excludeSelectors: CSS selectors ignored during capture.captureRoundedBorders: whether rendered border radius should be captured.
List discovered Wirebone components:
php artisan wirebones:listBuild all generated placeholders:
php artisan wirebones:buildBuild one or more components by Wirebone name:
php artisan wirebones:build --component=revenue-card
php artisan wirebones:build --component=revenue-card --component=user-tableClear generated placeholder files:
php artisan wirebones:clearShow the browser or print capture diagnostics while building:
php artisan wirebones:build --headed --debugThe published config/wirebones.php file controls capture, auth, generated output, and skeleton rendering.
Common options:
'breakpoints' => [375, 768, 1280],
'wait' => 800,
'viewport_height' => 900,
'compiled_path' => storage_path('framework/wirebones/views'),
'animation' => 'pulse', // pulse, shimmer, solid
'render_containers' => true,
'responsive_strategy' => 'viewport', // viewport, containerRendering values such as colors, animation, shimmer angle, and container rendering are baked into generated Blade files. Re-run wirebones:build after changing them.
If a captured route requires authentication, configure a build user and protect build mode with a token:
WIREBONES_BUILD_TOKEN=secret-build-token
WIREBONES_AUTH_USER_ID=1
WIREBONES_AUTH_GUARD=webWirebones will authenticate the Laravel request while build mode is active.
For applications that need browser-level auth, configure cookies, headers, or a Playwright storage state file:
'auth' => [
'guard' => env('WIREBONES_AUTH_GUARD', 'web'),
'user_id' => env('WIREBONES_AUTH_USER_ID'),
'cookies' => [
['name' => 'session', 'value' => env('WIREBONES_SESSION'), 'domain' => 'localhost', 'path' => '/'],
],
'headers' => [
'Authorization' => 'Bearer '.env('WIREBONES_API_TOKEN'),
],
'storage_state' => storage_path('app/wirebones-storage-state.json'),
],You may also pass cookies and headers directly to the build command:
php artisan wirebones:build \
--cookie="session=abc123" \
--header="Authorization: Bearer token"Wirebones includes a Vite plugin that watches changed Livewire component PHP files and Blade views, then rebuilds only affected skeletons.
Import the plugin from the Composer package:
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import wirebones from './vendor/mrfelipemartins/wirebones/vite/index.js'
export default defineConfig({
plugins: [
laravel({ input: ['resources/css/app.css', 'resources/js/app.js'], refresh: true }),
wirebones(),
],
})The Laravel app server must already be running. The plugin runs only during vite serve, debounces changes, and executes targeted builds like:
php artisan wirebones:build --component=revenue-cardGenerated placeholders are build artifacts. A typical deployment should:
- Install Composer and Node dependencies.
- Ensure Playwright Chromium is available in the build environment.
- Run the Laravel application so configured capture routes are reachable.
- Run
php artisan wirebones:build. - Run
php artisan view:cacheif your deployment caches views.
Wirebones ships a Laravel Boost skill at:
resources/boost/skills/wirebones-development/SKILL.md
When users run Laravel Boost with package skill discovery, Boost can install this skill so AI agents understand Wirebones conventions, commands, generated Blade artifacts, authenticated captures, and the Vite auto-rebuild workflow.