AKZN Notes

Archives for My Lazy and Forgetful Mind

How to Make Vite Build Work on Filament Page

How to Make Vite Build Work on Filament Page

Context: Filament 3 + Laravel 12 + Vite
Difficulty: Beginner
Prerequisites: Laravel 12, Filament 3, Vite configured

if this article here still cant make vite build used on filament 3. try follow this steps


Overview

When you want to use custom CSS/JS assets (built with Vite) in your Filament 3 admin panel, you need to register them through a custom Service Provider. This article shows you the complete setup.


Problem Statement

Issue: Custom CSS/JS files built with Vite don't appear in Filament pages.

Why This Happens:

  • Filament 3 has its own asset management system
  • Vite assets need to be registered with Filament's asset manager
  • The registration must happen at the right time in the application lifecycle

Solution Architecture

Vite Build → FilamentAsset::register() → Filament Pages
     ↓                ↓                      ↓
resources/js/app.css → Service Provider → Custom Assets Loaded
resources/js/app.js   → boot() method       in Filament

Step-by-Step Implementation

Step 1: Create FilamentServiceProvider

Location: app/Providers/FilamentServiceProvider.php

Complete Code:

<?php
namespace App\Providers;

use Filament\Support\Facades\FilamentAsset;
use Filament\Support\Assets\Css;
use Filament\Support\Assets\Js;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Vite;

class FilamentServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // Register assets only after app is fully booted
        $this->app->booted(function () {
            FilamentAsset::register([
                Css::make('custom-styles', Vite::asset('resources/css/app.css')),
                Js::make('custom-scripts', Vite::asset('resources/js/app.js')),
            ], 'custom');
        });
    }
}

Code Explanation:

Component Purpose
FilamentAsset::register() Register assets with Filament's asset manager
Css::make('custom-styles', ...) Register CSS file with unique name 'custom-styles'
Js::make('custom-scripts', ...) Register JS file with unique name 'custom-scripts'
Vite::asset(...) Resolve Vite asset path (dev or production)
'custom' Asset bundle name (can be any string)
$this->app->booted(function () {...}) Ensure registration happens after full boot

Step 2: Register Service Provider

Location: bootstrap/providers.php

Complete Code:

<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\Filament\AdminPanelProvider::class,
    App\Providers\EventServiceProvider::class,
    App\Providers\FilamentServiceProvider::class,  // ← Add this line
];

Why This Is Needed:

  • Laravel 12 uses bootstrap/providers.php to load service providers
  • Adding your provider here ensures it's loaded during application bootstrap
  • Order matters: Place it after core providers but before your custom providers

Step 3: Create Asset Files (If Not Exists)

Vite Entry Point: resources/js/app.js

import './bootstrap';
import '../css/app.css';

// Your custom JS for Filament pages
console.log('Filament custom scripts loaded');

// Example: Custom Alpine.js components
document.addEventListener('alpine:init', () => {
    Alpine.data('myComponent', () => ({
        open: false,
        toggle() {
            this.open = !this.open;
        }
    }));
});

CSS File: resources/css/app.css

/* Tailwind CSS imports */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Your custom styles for Filament */
.filament-custom-heading {
    @apply text-2xl font-bold text-gray-900;
}

/* Custom component styles */
.custom-card {
    @apply bg-white rounded-lg shadow-sm p-6;
}

Step 4: Configure Vite

Location: vite.config.js

Ensure your Vite config includes the Laravel plugin:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/js/app.js', 'resources/css/app.css'],
            refresh: true,
        }),
    ],
});

Note: This is the standard Laravel + Vite setup. No Filament-specific config needed here.


Step 5: Build Assets

Development Mode (Hot reload):

npm run dev

Production Build:

npm run build

This generates:

  • public/build/assets/ - Compiled assets
  • public/build/manifest.json - Asset mapping
  • public/build/hot - Hot reload file (dev only)

Step 6: Use in Filament Pages

In Your Custom Filament Page:

<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;

class MyCustomPage extends Page
{
    protected static string $view = 'filament.pages.my-custom-page';

    // Your custom page logic
}

In Blade View (resources/views/filament/pages/my-custom-page.blade.php):

<x-filament-panels::page>
    <div class="filament-custom-heading">
        <h1>My Custom Page</h1>
    </div>

    <div class="custom-card">
        <div x-data="myComponent">
            <button @click="toggle()">Toggle</button>
            <div x-show="open">Content</div>
        </div>
    </div>
</x-filament-panels::page>

How It Works:

  1. Filament loads the page
  2. Service Provider registers assets
  3. Vite resolves app.js and app.css
  4. Assets are injected into Filament's asset bundle
  5. Your custom CSS/JS is available on the page

Advanced Usage

Multiple Asset Bundles

You can register multiple asset bundles for different purposes:

FilamentAsset::register([
    // Admin panel styles
    Css::make('admin-styles', Vite::asset('resources/css/admin.css')),

    // Student portal styles
    Css::make('student-styles', Vite::asset('resources/css/student.css')),
], 'admin');

Conditional Registration

Register assets only on specific environments:

$this->app->booted(function () {
    if (app()->environment('production')) {
        FilamentAsset::register([
            Css::make('minified', Vite::asset('resources/css/app.css')),
        ], 'production');
    }
});

Using in Custom Resources

Add to your Filament Resource:

use Filament\Support\Facades\FilamentAsset;
use Filament\Support\Assets\Js;

class MyResource extends Resource
{
    public static function getPages(): array
    {
        return [
            // Your pages
        ];
    }

    // Register resource-specific assets
    public static function getEloquentQuery(): Builder
    {
        FilamentAsset::register([
            Js::make('resource-scripts', Vite::asset('resources/js/resource.js')),
        ]);

        return parent::getEloquentQuery();
    }
}

Troubleshooting

Issue: Assets Not Loading

Symptoms:

  • 404 errors for CSS/JS files
  • Custom styles not applied
  • JavaScript not executing

Solutions:

  1. Check if Vite is running (dev mode):

    npm run dev
  2. Clear Filament cache:

    php artisan filament:clear-cached-components
    php artisan config:clear
    php artisan view:clear
  3. Verify provider is registered:

    php artisan provider:cache
    php artisan optimize:clear
  4. Check if assets are built (production):

    npm run build
    ls -la public/build/assets/
  5. Verify Vite manifest exists:

    cat public/build/manifest.json

Issue: Assets Loading But Not Working

Symptoms:

  • Files load (no 404)
  • Styles/Scripts don't execute

Solutions:

  1. Check browser console for JavaScript errors

  2. Verify CSS specificity - Filament styles may override yours:

    /* Use !important sparingly */
    .my-custom-style {
     color: red !important;
    }
  3. Check Alpine.js timing - Ensure alpine:init fires after load:

    document.addEventListener('alpine:init', () => {
       // Your code here
    });

Issue: Hot Reload Not Working

Symptoms:

  • Changes to CSS/JS not reflecting
  • Need to manually refresh

Solutions:

  1. Ensure Vite dev server is running:

    npm run dev
  2. Check Vite port (default: 5173):

    netstat -an | grep 5173
  3. Verify @vite directive in Blade:

    @vite(['resources/js/app.js', 'resources/css/app.css'])

Performance Tips

Production Optimization

  1. Minify Assets:

    npm run build
  2. Enable Asset Versioning (automatic):

    • Vite adds hash to filenames: app-abc123.js
    • Cache busting handled automatically
  3. Use CDN for Static Assets:

    • Configure your web server (Nginx/Apache)
    • Serve public/build/ via CDN

Development Optimization

  1. Exclude Large Dependencies:
    In vite.config.js:

    export default defineConfig({
       resolve: {
           alias: {
               '@': '/resources/js',
           },
       },
       optimizeDeps: {
           exclude: ['laravel-vite-plugin'],
       },
    });
  2. Use Fast Refresh:

    • Already enabled by default
    • HMR (Hot Module Replacement) preserves component state

Best Practices

1. Asset Organization

resources/
├── css/
│   ├── app.css          # Main styles (Tailwind imports)
│   ├── admin.css        # Admin-specific styles
│   └── student.css      # Student portal styles
└── js/
    ├── app.js           # Main entry point
    ├── admin.js         # Admin-specific scripts
    └── student.js       # Student portal scripts

2. Naming Conventions

  • CSS Asset Names: Use descriptive kebab-case

    • 'admin-styles', 'student-styles'
    • 'css1', 'styles'
  • JS Asset Names: Use descriptive kebab-case

    • 'custom-scripts', 'chart-library'
    • 'js', 'scripts'

3. Asset Bundle Names

The second parameter ('custom') groups related assets:

// Bundle related assets together
FilamentAsset::register([
    Css::make('dashboard-css', Vite::asset('resources/css/dashboard.css')),
    Js::make('dashboard-js', Vite::asset('resources/js/dashboard.js')),
], 'dashboard-bundle');

4. Lazy Loading

Load heavy assets only when needed:

// In your page class
use Filament\Support\Facades\FilamentAsset;

public function mount(): void
{
    // Load chart library only on this page
    FilamentAsset::register([
        Js::make('charts', Vite::asset('resources/js/charts.js')),
    ]);
}

Migration from Mix to Vite

If you're migrating from Laravel Mix:

Before (Mix):

// webpack.mix.js
mix.js('resources/js/app.js', 'public/js')
   .sass('resources/css/app.css', 'public/css');

After (Vite):

// vite.config.js
export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/js/app.js', 'resources/css/app.css'],
        }),
    ],
});

Provider Changes:

// Old Mix way
{{ mix('css/app.css') }}

// New Vite way (no changes needed in Blade)
@vite(['resources/css/app.css'])

Summary Checklist

  • [x] Create FilamentServiceProvider.php
  • [x] Register assets in boot() method
  • [x] Add provider to bootstrap/providers.php
  • [x] Configure vite.config.js
  • [x] Create asset files (app.js, app.css)
  • [x] Build assets (npm run build or npm run dev)
  • [x] Clear caches (php artisan optimize:clear)
  • [x] Test in browser

Related Documentation


Last Updated: 2026-02-12
Laravel Version: 12
Filament Version: 3.x
Vite Version: 5.x


Quick Reference

Complete Working Example:

// app/Providers/FilamentServiceProvider.php
<?php
namespace App\Providers;

use Filament\Support\Facades\FilamentAsset;
use Filament\Support\Assets\Css;
use Filament\Support\Assets\Js;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Vite;

class FilamentServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->app->booted(function () {
            FilamentAsset::register([
                Css::make('custom-styles', Vite::asset('resources/css/app.css')),
                Js::make('custom-scripts', Vite::asset('resources/js/app.js')),
            ], 'custom');
        });
    }
}
// bootstrap/providers.php
<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\Filament\AdminPanelProvider::class,
    App\Providers\EventServiceProvider::class,
    App\Providers\FilamentServiceProvider::class,
];

That's it! Your Vite assets will now work seamlessly across all Filament pages.