Developing a Laravel package with Laravel Mix and Inertia.js

You can directly skip to “Installing Laravel Mix and Inertia.js” if you already know how to setup a package or have a package you’re working in.

Scaffolding our project

Let’s get started by scaffolding a project where we develop our package. Spin up your terminal and create a new Laravel project:

cd ~/Sites

laravel new our-awesome-package

cd our-awesome-package

Great, that should’ve taken a few seconds with Composer 2. Now, let’s create a basic setup for our package. For the sake of simplicity (and my personal preference) we’re going to use a template made by Spatie: spatie/package-skeleton-laravel this template takes care of the boring boilerplate stuff.

Also noteworthy: the template comes with a package called laravel-package-tools. This makes registering commands, routes and views as simple as chaining a few methods.

Okay, let’s make use of this:

mkdir packages

cd packages

git clone [email protected]:spatie/package-skeleton-laravel.git YOUR_PACKAGE_NAME

cd YOUR_PACKAGE_NAME

We almost have everything in place. Let’s finish this by running bash configure-skeleton.sh this will do the rest for us.

Once you’ve completed these steps you’ll have to include the package in your actual Laravel app. You’ll do this by

  1. Add it to your composer.json repositories array
  2. Require the local package

Open your project’s composer.json (not the one inside your package) and add the following:

"repositories": [
  {
    "type": "path",
    "url": "./packages/PACKAGE_DIRECTORY_NAME"
  }
],

Now we’re able to require the package by running composer require YOUR_VENDOR_NAME/YOUR_PACKAGE_NAME. Awesome, let’s proceed to the part what the blog is about.

Installing Laravel Mix and Inertia.js

First, we need to install our packages. Let’s start with that:

npm init -y

npm i -D @inertiajs/inertia @inertiajs/inertia-vue vue laravel-mix

composer require inertiajs/inertia-laravel

Let’s not forget to add our script to the package.json:

"scripts": {
    "development": "mix",
    "watch": "mix watch",
    "watch-poll": "mix watch -- --watch-options-poll=1000",
    "hot": "mix watch --hot",
    "production": "mix --production"
}

Right, that wasn’t difficult. We now have Inertia.js, Vue and Inertia for Laravel. I guess you also came this far before consulting this blog post.

Setting up Laravel Mix

Let’s create the webpack.mix.js configuration file which does the magic:

const mix = require('laravel-mix')

mix.setPublicPath('public').copy(
    'public',
    '../../public/vendor/YOUR_PACKAGE_NAME'
)

mix.js('resources/js/app.js', 'public/js')
    .vue({ version: 2 })
    .postCss('resources/css/app.css', 'public/css')

if (mix.inProduction()) {
    mix.version()
}

Got it? No worries. I’ll explain what’s happening. We’re setting the public path to public and copy over the whole public folder to our app’s public folder under the vendor/YOUR_PACKAGE_NAME name.

So, our app.js will resolve to https://ourapp.com/vendor/YOUR_PACKAGE_NAME/app.js, the same applies to app.css of course. We’re not done yet. Let’s continue with setting up Inertia.

Setting up Inertia

Cool, we can now continue with setting up Inertia. Let’s create an app.js entry inside resources/js/app.js and an empty resources/css/app.css so our Laravel Mix won’t break.

We’ll blindly follow the Inertia docs until we hit our next roadblock:

// resources/js/app.js

import { App, plugin } from '@inertiajs/inertia-vue'
import Vue from 'vue'

Vue.use(plugin)

const el = document.getElementById('app')

new Vue({
    render: h =>
        h(App, {
            props: {
                initialPage: JSON.parse(el.dataset.page),
                resolveComponent: name => require(`./Pages/${name}`).default,
            },
        }),
}).$mount(el)

And our middleware of course. Make sure you set the $rootView correctly:

<?php

// src/Http/Middleware/HandleInertiaRequests.php

namespace YOUR_VENDOR_NAME\YOUR_PACKAGE_NAME\Http\Middleware;

use Illuminate\Http\Request;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
{
    /**
     * The root template that's loaded on the first page visit.
     *
     * @see https://inertiajs.com/server-side-setup#root-template
     * @var string
     */
    protected $rootView = 'PACKAGE_NAME::app';

    /**
     * Determines the current asset version.
     *
     * @see https://inertiajs.com/asset-versioning
     * @param  \Illuminate\Http\Request  $request
     * @return string|null
     */
    public function version(Request $request)
    {
        return parent::version($request);
    }

    /**
     * Defines the props that are shared by default.
     *
     * @see https://inertiajs.com/shared-data
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function share(Request $request)
    {
        return array_merge(parent::share($request), [
            //
        ]);
    }
}

We’re almost set. All what’s left is creating a route, view and set the middleware. So let’s do that.

First, register a base view for our Inertia app:

<!-- resources/views/app.blade.php -->

<!DOCTYPE html>
<html lang="en">

<head>
    <!-- Don't forget to use your package name -->
    <link rel="stylesheet" href="{{ mix('css/app.css', 'vendor/YOUR_PACKAGE_NAME') }}">
    <script src="{{ mix('js/app.js', 'vendor/YOUR_PACKAGE_NAME') }}" defer></script>
</head>

<body>
    @inertia
</body>

</html>

Then we’ll create the routes:

<?php

// routes/web.php

Route::middleware(['web', HandleInertiaRequests::class])->get('our-package', function () {
    return inertia('Home');
});

And after that we’ll create the Vue component:

<!-- resources/js/Pages/Home.vue -->

<template>
    <div>We did it!</div>
</template>

Let’s see if it works by running npm run watch and visiting /our-package. That’s it.

I’d recommend to to check out these links if you want to know more or if it’s still not working:

  • Inertia.js documentation
  • Laravel package documentation
  • Spatie’s Laravel package skeleton
  • Spatie’s Laravel package tools
  • Laravel package development guide