Migrating Laravel 9 with Inertia.js + Vue.js + Tailwind CSS from Laravel Mix (Webpack) to Vite
Tags: vite, laravel, inertiaj, vue
Published: 2022-10-23 14:30:31

Back in February this year I was writing [this](https://dev.to/geowrgetudor/setting-up-laravel-with-inertiajs-vuejs-tailwind-css-21pc) guide on how to setup Inertia.js + Vue.js + Tailwind CSS on a brand new Laravel 8 project.
That guide also worked for the early releases of Laravel 9, but a few months later Laravel took a strange turn switching from Webpack to Vite in a minor release.
While Webpack was and still is ok for anyone who's using it, I was surprise to see this sudden shift during a minor release.
Aaaaanyway, let's move on and dig into the fun stuff.

## What's Vite and how does it work?
Vite is a great open-source frontend tool built by Evan You, the same guy behind Vue. It offers live reload out of the box, really user friendly and easy to understand syntax and it's faaaast. You can find more info about "why" is it great [here](https://vitejs.dev/guide/why.html).

## Vite vs Laravel Mix (Webpack). Ease of use
Here are just my 2 cents. I've been using Webpack since forever and I can say for sure that switching to Vite was like moving from a good apartment to a penthouse. Vite is so much easy to use.

## Installing Vite and Vite related packages
Before we start, let's remove all the Laravel Mix/Webpack related stuff installed in the previous guide. So we can get rid of the following packages:
```
npm uninstall laravel-mix webpack-shell-plugin-next
```
Next we need to add all the Vite related packages. By default, Laravel ships only with the `vite` package but we need a bit more in order to support Inertia.js, Tailwind CSS and Vue.
```
// Make sure your have Node v.16+ installed
npm install --save-dev vite laravel-vite-plugin @vitejs/plugin-vue
```

## Setting up vite.config.js
First we need to remove the old `webpack.mix.js` file because we no longer need it. If you have other stuff in there (not related to this guide) make sure you port them to your new `vite.config.js` file.
Now let's create a blank new `vite.config.js` file and add the default scaffolding:
```
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
    ],
});
```
Next we have to import the Vue plugin for Vite and include it into the plugins section. We're also going to remove the `app.css` input since we'll include the CSS in our `app.js`.
So our new config will look like this:
```
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/js/app.js'],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
});
```

## Post CSS config
Since we're importing `app.css` directly into Vue, we're going to need a `postcss.config.js` file to define our PostCSS plugins:
```
module.exports = {
    plugins: [
        require('postcss-import'),
        require('tailwindcss')
    ]
}
```
If you don't have `postcss` installed, feel free to add it:
```
npm install --save-dev postcss-import
```
## Let's not forget about Ziggy
We've used Ziggy in our previous guide and we're still going to use it now. In order for Vite to resolve it we have to define some aliases in `vite.config.js`.

So our final version of the config will look like this:
```
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/js/app.js'],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
    resolve: {
        alias: {
            'ziggy': '/vendor/tightenco/ziggy/src/js',
            'ziggy-vue': '/vendor/tightenco/ziggy/src/js/vue'
        },
    },
});
```

## Adding assets to our main template
When we were using Webpack, we had include multiple lines of code in our main templating. It was looking like this:
```
<link href="{{ asset(mix('css/app.css')) }}" rel="stylesheet">
<script src="{{ asset(mix('js/manifest.js')) }}" defer></script>
<script src="{{ asset(mix('js/vendor.js')) }}" defer></script>
<script src="{{ asset(mix('js/app.js')) }}" defer></script>
```
We had the `app.css` file, the `manifest.js`, `ventor.js` and lastly our `app.js`. While this was not bad at all, with Vite things are more simpler.
All we have to do is to replace the previously mentioned lines with the following Blade directive:
```
@vite('resources/js/app.js') 
```

## Adapting your Vue files
First you need to know that `require()` is no longer available while using Vite. So you will need to change all your code that does that.
So for example this:
```
window.Pusher = require('pusher-js');
```
Will become this:
```
import Pusher from 'pusher-js';
window.Pusher = Pusher;
```

`.vue` file extention is required for all your imports. So this will throw an error:
```
import Icon from "@/components/Icon"; 
```
You will need to add the file extention:
```
import Icon from "@/components/Icon.vue"; 
```
_Note_ that the `@` alias is already defined in the Laravel plugin, so you no longer have to define it.

## Finally, let's deal with app.js
This is our old `app.js` file that we used in the previous guide. It won't work out of the box, so we'll have to modify it a little bit.
```
import { createApp, h } from "vue";
import { createInertiaApp, Link, Head } from "@inertiajs/inertia-vue3";
import { InertiaProgress } from "@inertiajs/progress";

import { ZiggyVue } from "ziggy";
import { Ziggy } from "./ziggy";

InertiaProgress.init();

createInertiaApp({
    resolve: async (name) => {
        return (await import(`./Pages/${name}`)).default;
    },
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .component("Link", Link)
            .component("Head", Head)
            .mixin({ methods: { route } })
            .mount(el);
    },
});
```

We need to import `resolvePageComponent` from the Laravel plugin and change our `resolve` function + to change the `ZiggyVue` import + to import our CSS. So the final version will look like this:

```
import { createApp, h } from "vue";
import { createInertiaApp, Link, Head } from "@inertiajs/inertia-vue3";
import { InertiaProgress } from "@inertiajs/progress";
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';

import { ZiggyVue } from "ziggy-vue";
import { Ziggy } from "./ziggy";
import '../css/app.css';

InertiaProgress.init();

createInertiaApp({
    resolve: async (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .component("Link", Link)
            .component("Head", Head)
            .mixin({ methods: { route } })
            .mount(el);
    },
});
```
That's pretty much it.

## Building your app
Last thing we need to do is to change our `package.json`'s scripts.
```
{
    "dev": "vite",
    "build": "vite build"
}
```
Now, in order to build you will have to firstly generate the `ziggy.js` file by running:
```
// You can find this command in the previous guide
php artisan ziggy:generate resources/js/ziggy.js
```
Then you can run the `dev` or `build`:
```
npm run dev
```

Also, make sure you clear your view cache because this might cause some issues after the migrations: `php artisan view:cache`.

For more info you can always check the official Laravel's migration guide [here](https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md#migrating-from-laravel-mix-to-vite).

## Extra
If you want to run commands during Vite compilation you can use [innocenzi/vite-plugin-run](https://github.com/innocenzi/vite-plugin-run). This will make it easy to run `php artisan ziggy:generate resources/js/ziggy.js` whenever your routes get changed or when deploying to production.

#### Support & follow me
| [![Buy me a coffee](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/geowrgetudor) | [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/geowrgetudor) | [![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/geowrgetudor) | [![Linkedin](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://linkedin.com/in/geowrgetudor) |
| ------------- | ------------- | ------------- | ------------- |