DEV Community

Cover image for Migrating Laravel 9 with Inertia.js + Vue.js + Tailwind CSS from Laravel Mix (Webpack) to Vite
George Tudor
George Tudor

Posted on • Edited on

Migrating Laravel 9 with Inertia.js + Vue.js + Tailwind CSS from Laravel Mix (Webpack) to Vite

Back in February this year I was writing this 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.

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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,
        }),
    ],
});
Enter fullscreen mode Exit fullscreen mode

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,
                },
            },
        }),
    ],
});
Enter fullscreen mode Exit fullscreen mode

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')
    ]
}
Enter fullscreen mode Exit fullscreen mode

If you don't have postcss installed, feel free to add it:

npm install --save-dev postcss-import
Enter fullscreen mode Exit fullscreen mode

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'
        },
    },
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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') 
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

Will become this:

import Pusher from 'pusher-js';
window.Pusher = Pusher;
Enter fullscreen mode Exit fullscreen mode

.vue file extention is required for all your imports. So this will throw an error:

import Icon from "@/components/Icon"; 
Enter fullscreen mode Exit fullscreen mode

You will need to add the file extention:

import Icon from "@/components/Icon.vue"; 
Enter fullscreen mode Exit fullscreen mode

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);
    },
});
Enter fullscreen mode Exit fullscreen mode

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);
    },
});
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Then you can run the dev or build:

npm run dev
Enter fullscreen mode Exit fullscreen mode

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.

Extra

If you want to run commands during Vite compilation you can use 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 Twitter GitHub Linkedin

Top comments (1)

Collapse
 
frikishaan profile image
Ishaan Sheikh

Hi, where does the route mixin come from?