inventor96/inertia-mako
| Install | |
|---|---|
composer require inventor96/inertia-mako |
|
| Latest Version: | v1.5.1 |
| PHP: | ~8.1.0|~8.2.0|~8.3.0 |
| License: | MIT |
| Last Updated: | Apr 3, 2026 |
| Links: | GitHub · Packagist |
Inertia.js Mako Adapter
An Inertia.js server-side adapter for the PHP Mako framework.
The examples below are for Vue.js.
Installation
-
Install the composer and npm packages:
composer create-project mako/app <project-name> # from mako's documentation cd <project-name> composer require inventor96/inertia-mako npm install --save-dev @inertiajs/vue3 @inertiajs/vite @vitejs/plugin-vue laravel-vite-plugin vite vueYes, the laravel vite plugin is intentional. We could create our own, but that would pretty much be reinventing the wheel, or just changing the name while the underlying code is untouched. Note that when running
npm run devlater, the Laravel plugin will report theAPP_URLas undefined, but that's OK for our situation. -
Set other npm configs:
package.json{ "private": true, "type": "module", "scripts": { "dev": "vite", "build": "vite build", "serve": "vite preview" }, ... } -
Create the vite config:
vite.config.jsimport { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import inertia from '@inertiajs/vite'; import vue from '@vitejs/plugin-vue'; import path from 'path'; export default defineConfig({ plugins: [ laravel({ input: 'app/resources/js/app.js', refresh: true, }), inertia(), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false, }, }, }), ], resolve: { alias: { '@': path.resolve(__dirname, 'app/resources/views'), }, }, build: { outDir: 'public', assetsDir: 'build', emptyOutDir: false, }, });Notes about the
buildconfig:- Standard practice is to set
outDirto thepublicdirectory, since that's where Mako serves static assets from. assetsDircan be set to whatever you want, butbuildis a common choice that doesn't conflict with Mako's defaultassetsdirectory.- You should probably add this directory to your
.gitignorefile (and other ignore files), since it will be generated by Vite and doesn't need to be committed to version control. - You could leave it as the default
assets, but that would make it harder to distinguish between Vite assets and Mako's or your own in any ignore files.
- You should probably add this directory to your
emptyOutDirshould be set tofalseto prevent Vite from deleting the entire public directory on each build. We want to keep theindex.phpfile and any other static assets in there. As long as your ignore files are configured correctly, you shouldn't have to worry about any leftover files from the build process causing issues.
- Standard practice is to set
-
Create the JS app file:
app/resources/js/app.jsimport { createInertiaApp } from '@inertiajs/vue3' createInertiaApp({ pages: '../views/Pages', }); -
Enable the package in Mako:
app/config/application.php[ 'packages' => [ 'web' => [ inventor96\Inertia\InertiaPackage::class, ], ], ]; -
Register the middlewares:
app/http/routing/middleware.php$dispatcher->registerGlobalMiddleware(inventor96\Inertia\InertiaCsrf::class); $dispatcher->registerGlobalMiddleware(inventor96\Inertia\InertiaInputValidation::class); $dispatcher->registerGlobalMiddleware(inventor96\Inertia\InertiaMiddleware::class); // optionally, define the middleware order. e.g.: $dispatcher->setMiddlewarePriority(inventor96\Inertia\InertiaCsrf::class, 50); $dispatcher->setMiddlewarePriority(inventor96\Inertia\InertiaInputValidation::class, 60); $dispatcher->setMiddlewarePriority(inventor96\Inertia\InertiaMiddleware::class, 70); -
Create a JSconfig so your IDE knows where things are (optional):
jsconfig.json{ "compilerOptions": { "paths": { "@/*": ["./app/resources/views/*"] } }, "exclude": ["node_modules", "public"] }
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. This config is relative
* to the `app/resources/views` directory.
* e.g. `'app'` would resolve to `resources/views/app.tpl.php`.
*/
'html_template' => 'inertia::default',
];
For vite-specific configurations, create a config file at app/config/packages/inertia/vite.php.
<?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 vue's
* `template.transformAssetUrls.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' => '/',
];
Also, configuration for CSRF protection can be defined in app/config/packages/inertia/csrf.php.
<?php
return [
/*
* Use a shared page prop for passing CSRF errors to the
* frontend. When set to `false`, the middleware will
* throw an `InvalidTokenException`. If set to any other
* value, the middleware will populate that prop with the
* CSRF error message. Dot notation can be used to set
* nested props. To tap into the form validation errors,
* you can use the `inertia_errors` prop.
*/
'use_prop' => false,
/*
* The lifetime of the cookie in seconds. 0 means "until
* the browser is closed".
*/
'cookie_ttl' => 0,
'cookie_options' => [
/*
* The path on the server in which the cookie will
* be available on. If set to '/', the cookie will
* be available within the entire domain. If set to
* '/foo/', the cookie will only be available within
* the /foo/ directory and all sub-directories.
*/
'path' => '/',
/*
* The domain that the cookie is available to. To
* make the cookie available on all subdomains of
* example.org (including example.org itself) then
* you'd set it to '.example.org'.
*/
'domain' => '',
/*
* Indicates that the cookie should only be
* transmitted over a secure HTTPS connection from
* the client. When set to TRUE, the cookie will
* only be set if a secure connection exists. On
* the server-side, it's on the programmer to send
* this kind of cookie only on secure connection
* (e.g. with respect to $this->request->isSecure()).
*/
'secure' => false,
/*
* When TRUE the cookie will be made accessible only
* through the HTTP protocol. This means that the
* cookie won't be accessible by scripting languages,
* such as JavaScript. Since the cookie is likely needed
* by the JavaScript HTTP library in the frontend, it is
* highly recommended to set this to FALSE.
*/
'httponly' => false,
/*
* The supported values are 'Lax', 'Strict' and 'None'.
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
*/
'samesite' => 'Lax',
],
];
Using a Custom html_template
You will probably want to create your own html_template at some point in your project. You can do so with any renderer of your choosing (other than the InertiaRenderer). For example, to use a standard Mako template, you could create a file at app/resources/views/app.tpl.php, and then update the inertia.php config file to set 'html_template' => 'app'.
There are 3 values passed to the template from the InertiaRenderer. You can add to these using built-in Mako functionality and assigning props to the template.
$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, andpreload. You have to use at least thejsproperty 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" />
{{ raw:$tags->preload }}
{{ raw:$tags->css }}
{{ raw:$tags->js }}
</head>
<body>
<noscript>Your browser does not support JavaScript or it is disabled. Please enable JavaScript to use this application.</noscript>
<script data-page="app" type="application/json">{{ raw:$page }}</script>
<div id="app"></div>
</body>
</html>
If you are using Inertia v2, you will need to change the way the page data is passed to the frontend. Instead of using a script tag, you should populate a data-page attribute on your mount element. For example:
<div id="app" data-page="{{ attribute:$page }}"></div>
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 could 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 besides an automatic Pages/ prefix. 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 (the array is requirement is due to how Mako configs work).
Commit Hash Versioning
One common way to version assets is to use the commit hash of the current git commit. You can do this by creating a file at app/config/packages/inertia/version.php that looks like this:
<?php
return (function() {
// this fallback will only be used if the git commit hash cannot be found.
// this will cause a full page load on almost every request, so it's not ideal.
// hopefully this will only be used when you first create your repo, and never again once you've made your first commit.
$commit_hash = date('YmdHis');
if (file_exists(__DIR__ . '/../../../../.git/HEAD')) {
$head_file = file_get_contents(__DIR__ . '/../../../../.git/HEAD');
if (strpos($head_file, 'ref: ') === 0) {
$ref_file = trim(substr($head_file, 5));
if (file_exists(__DIR__.'/../../../../.git/' . $ref_file)) {
$commit_hash = trim(file_get_contents(__DIR__.'/../../../../.git/' . $ref_file));
}
} else {
$commit_hash = trim($head_file);
}
}
return [$commit_hash];
})();
This approach checks the filesystem rather than using the git command, so it should work on any system that has a .git directory. If you are using a CI/CD pipeline, you may need to adjust the path to the .git directory.