inventor96/inertia-mako

The Mako adapter for Inertia.js.

v1.0.0 2024-09-30 11:12 UTC

This package is auto-updated.

Last update: 2024-10-30 11:29:57 UTC


README

An Inertia.js server-side adapter for the PHP Mako framework.

Installation

  1. Install the composer and npm packages:

    composer require inventor96/inertia-mako
    npm install @inertiajs/inertia @inertiajs/vue3 @vitejs/plugin-vue laravel-vite-plugin vite vue

    Yes, the laravel vite plugin is intentional. We could create our own, but that would pretty much be reinventing the wheel. Note that when running npm run dev later, the Laravel plugin will report the APP_URL as undefined, but that's OK for our situation.

  2. Set other npm configs: package.json:

    {
        "private": true,
        "type": "module",
        "scripts": {
            "dev": "vite",
            "build": "vite build",
            "serve": "vite preview"
        },
        "dependencies": {
            ...
        }
    }
  3. Create the vite config: vite.config.js:

    import { defineConfig } from 'vite';
    import laravel from 'laravel-vite-plugin';
    import vue from '@vitejs/plugin-vue';
    
    export default defineConfig({
        plugins: [
            laravel({
                input: 'app/resources/js/app.js',
                refresh: true,
            }),
            vue({
                template: {
                    transformAssetUrls: {
                        base: null,
                        includeAbsolute: false,
                    },
                },
            }),
        ],
        resolve: {
            alias: {
                '@': 'app/resources/js',
            },
        },
    });
  4. Create the JS app file: app/resources/js/app.js:

    import { createApp, h } from 'vue'
    import { createInertiaApp } from '@inertiajs/vue3'
    import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'
    
    createInertiaApp({
        resolve: (name) => resolvePageComponent(`../views/Pages/${name}.vue`, import.meta.glob('../views/Pages/**/*.vue')),
        setup({ el, App, props, plugin }) {
            createApp({ render: () => h(App, props) })
                .use(plugin)
                .mount(el)
        },
    })
  5. Enable the package in Mako:
    app/config/application.php:

    [
        'packages' => [
            'web' => [
                inventor96\Inertia\InertiaPackage::class,
            ],
        ],
    ];
  6. Register the middleware: app/http/routing/middleware.php:

    $dispatcher->registerGlobalMiddleware(inventor96\Inertia\InertiaMiddleware::class);

Configuration

If you would like to override the default configuration, create a new file at app/config/packages/inertia/inertia.php.

The following configuration items and their defaults are as follows:

<?php
return [
    /**
     * The view to use when rendering the full HTML page
     * for the initial response to the browser.
     */
    'html_template' => 'inertia::default',

    /**
     * The initial title for the full HTML page.
     */
    'title' => 'Loading...',
];

For vite-specific configurations, create a vite.php config file in the same directory.

<?php
return [
    /**
     * The path to the manifest file generated by Vite.
     * Only needed if you change the default path in Vite,
     * otherwise the key should be omitted entirely.
     */
    //'manifest' => null,

    /**
     * The path to the hot module replacement file generated
     * by Vite. Only needed if you change the default path in
     * Vite, otherwise the key should be omitted entirely.
     */
    //'hot_file' => null,

    /**
     * The base path for the Vite assets. Should match the
     * `base` option in your Vite configuration, but could
     * also point to a CDN or other asset server, if you are
     * serving assets from a different domain.
     */
    'base_path' => '/',
];

Using a Custom html_template

You will probably want to create your own html_template at some point in your project. There are 3 values passed to the template from the InertiaRenderer. You can add to these using built-in Mako functionality.

  • $title: Just a pass-thru of the title config var above. This is optional to use.
  • $page: The JSON Inertia page object. You have to use this somewhere for Inertia to work.
  • $tags: The HTML tags for Vite resources. It contains three string properties: js, css, and preload. You have to use at least the js property somewhere for Inertia to work.

Here is the default page used in this inertia-mako package:

<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    <title>{{ $title }}</title>
    {{ raw:$tags->preload }}
    {{ raw:$tags->css }}
    {{ raw:$tags->js }}
</head>
<body>
    <div id="app" data-page='{{ raw:$page }}'></div>
</body>
</html>

Coding Your App

The idea of this InertiaJS adapter is to utilize existing Mako framework functionality. As such, it's built to have the Vue files be organized under app/resources/views/. Pages should be under the Pages/ folder. For example:

app/
    resources/
        views/
            Components/
                ...
            Layouts/
                ...
            Pages/
                Welcome.vue
                ...

In your routes or controllers, you can use the Mako ViewFactory::render() method to handle the InertiaJS response, prefixing the path with Pages/. e.g. $view->render('Pages/Welcome').

The Inertia class is registered in the Mako dependency injection container under the inertia key. So as an alternative to using the ViewFactory with the path prefix, you call $this->inertia->render('Welcome'). This is just a wrapper around the original method, so there's really no difference under the hood. It's just there for personal preference sake.

Asset Versioning

Inertia.js features asset versioning to mitigate stale client-side caching. To indicate the server-side version, create a file at app/config/packages/inertia/version.php that functions like the following:

<?php
return ['1.0'];

You can make that file do whatever you need to come up with your verison. The only requirement is that it ultimately returns an array with a single string value.