Laravel Jetstream with Inertia.js not recognizing changes

Published 11 September 2020 14:23 (4 minute read)

When developing your project using Laravel Jetstream and are using Inertia.js, you have to version your HTTP requests. This will force the front-end to refresh the page and all static assets like javascript/css.

To force Inertia.js to reload all static assets, can use the version method (for example, in your AppServiceProvider):

Inertia::version('random-string-to-identify-this-unique-application-version');

After you added the string to your application it will include this as a header in the responses made by Inertia (so, not the first request you make to the application - only the following requests made within your Inertia application).

When users are using your application and you deploy a new version, they have to visit a new page to force a fresh page request.

Laravel Mix and Laravel Jetstream with Inertia

When you are using a service like Laravel Mix to build your front-end assets and use asset versioning (this toggle cache-busting), you have a file that contains a list of all static assets in your application. This file is generated by Laravel Mix based on an md5 hash of the content of that unique file.

This is how your webpack.mix.js file may look like when using Laravel Mix versioning.

const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        require('postcss-import'),
        require('tailwindcss'),
    ])
    .version(); // < --- added

Then you can use the file "public/mix-manifest.json" to identify changes to your front-end assets to enforce loading new assets.

Take a look at the AppServiceProvider.php boot method. It checks if the mix-manifest.json exists in the public folder. If so, it will load the content and make an md5 hash of the file' content and set it as the Inertia version:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\File; // <-- added
use Illuminate\Support\ServiceProvider;
use Inertia\Inertia; // <-- added

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        if(File::exists($mixManifestFile = public_path('mix-manifest.json'))) {
            Inertia::version(function () use ($mixManifestFile) {
                return md5_file($mixManifestFile);
            });
        }
    }
}

Cache Inertia version for speed improvements

When you have a lot of files or big mix-manifest.json file, it can take some time to check if the file exists, load the content, make a hash with md5 and set it as an Inertia version.

You can make a special cache key that will handle the Inertia version for you. This will speed up the application when you have a big mix-manifest.json. There are many ways to do this, but here's one of the possibilities you could implement.

// file: app/Console/Commands/InertiaVersionFlushCommand.php
<?php

namespace App\Console\Commands;

use App\Providers\AppServiceProvider;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;

class InertiaVersionFlushCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'inertia:version-flush';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Make a unique Inertia version for this build based on the public/mix-manifest.json file.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $mixManifestFile = public_path('mix-manifest.json');

        // check if the mix manifest exists
        if(!File::exists($mixManifestFile)) {
            $this->error("Mix manifest cannot be found at `{$mixManifestFile}`.");
            return;
        }
        
        // generate the md5 hash of the file
        $inertiaVersionHash = md5_file($mixManifestFile);
        
        // store the md5 hash as a new Inertia version
        Cache::put(AppServiceProvider::getInertiaVersionCacheKey(), $inertiaVersionHash);
    }
}

And also, update the AppServiceProvider:

// file: app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;
use Inertia\Inertia;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Inertia::version(self::getInertiaVersionFromCache());
    }

    public static function getInertiaVersionCacheKey() {
        return 'inertia-version';
    }

    public static function getInertiaVersionFromCache() {
        return Cache::get(self::getInertiaVersionCacheKey());
    }
}

During the deployment of your application (for example on production), you can call the command and it will set the new Inertia version based on the md5 hash of mix-manifest.json. This is saved forever in the cache until you refresh it (or remove the cache key).

php artisan inertia:version-flush

Ps, if you are not running the command, it is not setting the Inertia version on the requests, this blocks the cache-busting of static files.

If you have any questions, don't hesitate to contact me.

Robin Dirksen

Robin Dirksen

On my blog, you can find articles that I've found useful or wanted to share with anyone else.

If you want to know more about this article or just want to talk to me, don't hesitate to reach out.