Your approach to loading page-specific assets in a Laravel application using Vite is quite reasonable. You've created a helper to read the Vite manifest and retrieve the correct versioned asset path, and you're sharing a function across all views to use this helper. This allows you to push page-specific scripts onto the stack without reloading the Vite client multiple times.
However, there are a few improvements and considerations you might want to take into account:
-
Caching the Manifest: Since the manifest file doesn't change between requests, you can cache its contents to avoid reading the file from the disk on every request. This can be done using Laravel's cache system.
-
Error Handling: Ensure that your code gracefully handles any errors that might occur when reading the manifest file or if the asset is not found in the manifest.
-
Hot Module Replacement (HMR): To retain HMR functionality, you might want to check if the application is in development mode and handle the asset inclusion differently in that case.
Here's an updated version of your AssetHelpers class with caching implemented:
namespace App\Helpers;
use Illuminate\Support\Facades\Cache;
class AssetHelpers
{
public static function get_assets_manifest()
{
return Cache::remember('assets_manifest', 3600, function () {
$manifest_path = public_path('build/manifest.json');
if (is_file($manifest_path)) {
return json_decode(file_get_contents($manifest_path), true);
}
return [];
});
}
public static function get_asset_from_manifest($filename = null)
{
$assets_map = self::get_assets_manifest();
return isset($assets_map[$filename]) ? asset('build/' . $assets_map[$filename]['file']) : '';
}
}
In your AppServiceProvider, you can check for the environment and decide whether to use the cached manifest or read it directly for HMR:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
View::composer('*', function ($view) {
$lr_get_asset = function ($asset_path = null) {
if (app()->environment('local')) {
// Clear the cache in local development to support HMR
Cache::forget('assets_manifest');
}
return AssetHelpers::get_asset_from_manifest($asset_path);
};
$view->with('lr_get_asset', $lr_get_asset);
});
}
}
And in your views, you can continue to use the @push directive as you have been:
@push('scripts')
<script src="{{ $lr_get_asset('resources/js/seed-create.js') }}"></script>
@endpush
This solution should provide a more efficient way to handle assets and maintain HMR support during local development. Remember to handle any potential exceptions and provide fallbacks where necessary.