Problem Statement
Consider a Laravel application that started long ago, before Inertia JS came into existence. And the project might have already been using Vue or blade template to develop the user interface. But the complexity to build a perfect SPA (single page application) with only Vue and blade template is really frustrating.
Besides that, you might hear about Inertia JS or even, have worked with this technology and got impressed with the SPA feature that Inertia JS provides. It removes the complexity of state management on the front end of the application i.e Vue side. And you want to use this cool technology within your legacy project, but are afraid to integrate it because of the complexity of the project. There could be so many breaking changes that it might affect all of the features. Sometimes you might even need to upgrade dependencies as well.
So, in this article, I would like to give an idea in which we could migrate our old legacy Laravel Vue or blade-based project into Inertia JS-based SPA, without affecting any previous functionality.
Note: Our frontend part is written in Vue 2 and tailwind CSS 2, and I would like to write my new pages of the application in Vue 3 and Tailwind CSS 3.
Solution
So at first Let's check out a new branch in our project.
git checkout -b inertia-experiment
Let's create a new directory inertia
in the root of the projects and go inside of it.
mkdir inertia & cd inertia
Initialize a new yarn project inside of it.
yarn init
After completion of the creation of the new yarn project, package.json
file will be created inside of it.
The next step would be adding vue 3
along with @vue/compiler-sfc
and vue-loader
as dependencies
yarn add vue@latest @vue/compiler-sfc vue-loader
and laravel-mix
to compile the assets.
yarn add laravel-mix -D
After installing laravel mix, let's create a file webpack.mix.js
in the current directory, in which you can write instructions to compile your assets, which looks like.
// webpack.mix.js
const mix = require("laravel-mix")
mix.css("css/app.css", "inertia/css")
.js("js/app.js", "inertia/js").vue({ version: 3 })
.sourceMaps()
The next step would be to create two folders js
and css
and create app.js
file inside of js
and app.css
inside of CSS folder.
Now let's install inertia js on client-side for Vue 3:
yarn add @inertiajs/inertia @inertiajs/inertia-vue3
and update recently created app.js
file to initialize the client-side framework with the base Inertia component.
// app.js
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/inertia-vue3'
createInertiaApp({
resolve: name => require(`./Pages/${name}`),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})
Now let's add some scripts in package.json
to compile the assets as.
// package.json
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production"
},
The next step would be to add inertia js on the server side.
composer require inertiajs/inertia-laravel
Let's create a views
folder inside our inertia
folder and add a root template file app.blade.php
<!-- /inertia/views/app.blade.php -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link href="{{ mix('/css/app.css') }}" rel="stylesheet" />
<script src="{{ mix('/js/app.js') }}" defer></script>
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
Now publish a middleware
php artisan inertia:middleware
Instead of adding Inertia middleware to web
middleware group, It is a good idea to apply only in inertia related route.
Let's define a example route and apply the App\Http\Middleware\HandleInertiaRequests
middleware to that route.
Route::middleware(HandleInertiaRequests::class)
->get("/inertia", function () {
return Inertia::render("Agent/Home/Index");
});
The remaining problem here is that we defined our root templates outsides of the Laravel default resources directory. So add the custom views path into Laravel view config.
// config/view.php
<?php
return [
....
'paths' => [
resource_path('views'),
base_path('inertia/views')
],
....
Now we still have to configure the public paths of assets. Laravel can only access the public folder for assets, so we must produce our asset files into the public folder after compilation so.
Let's update webpack.mix.js
file and add mix.setPublicPath("../public")
// webpack.mix.js
const mix = require("laravel-mix")
mix.setPublicPath("../public")
mix.css("css/app.css", "inertia/css")
.js("js/app.js", "inertia/js").vue({ version: 3 })
.sourceMaps()
as the above configuration published our files into public/inertia/css
and public/inertia/js
directory so we need to update root template accordingly.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link href="{{ mix('/inertia/css/app.css') }}" rel="stylesheet" />
<script src="{{ mix('inertia/js/app.js') }}" defer></script>
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
Now we can add our application pages inside of Pages directory like
// inertia/js/Pages/Agent/Index.vue
<template>
<div>
Hello From Other sides.
</div>
</template>
<script>
export default {
name: "Index",
}
</script>
compile the project inside the inertia directory as:
yarn watch
and access the URL: {base}/inertia
and you can see the text Hello From Other sides.
Conclusion:
This approach of migrating into Inertia JS is quite easy as we don't need to completely migrate the whole application. We can migrate into SPA one page at a time, secondly, the new inertia-related code is completely isolated from the previous Vue/blade components, so there wouldn't be any breaking changes in the system. No need to worry about dependencies as well.