# Migrating Laravel / Vue App To Inertia JS

### 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.
```bash
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.
```bash
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

```bash
yarn add vue@latest @vue/compiler-sfc vue-loader
```
and `laravel-mix` to compile the assets.
```bash
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.

```javascript
// 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:
```bash
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.
```js
// 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.
```json
// 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.
```php
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.

```php
// 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") ` 
```js
// 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.
```php+HTML
<!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
```vue
// 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:
```bash
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.
