Laravel 9.x with Vue, Tailwind, and Vue-Router

Elevate your Laravel apps with Vue, Tailwind, and Vue Router

Do you keep your backend completely separate from your front-end or do you try to integrate the Vue and Laravel structure into one project? I prefer the latter. It’s not as intuitive as it should be. I used to love the UI presets before, where you can select either React or Vue and move on. Although not terrible, we do need to set this up properly.

 

Installing Vue

First, setup a new Laravel projects. I’m using Docker on a Mac, so my installation is pretty straightforward.

curl -s "https://laravel.build/laravel-vue" | bash

Once installed, cd into your directory and run ./vendor/bin/sail up to start your project.

resources/welcome.blade.php

Prepare the welcome.blade.php file by opening it and deleting most of the code from there. You’re just going to want a div with an id="app" attribute.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">

    </head>
    <body class="antialiased">
        <div id="app"></div>
    </body>
</html>

We’ll need to revisit the welcome view soon.

vitejs/plugin-vue

In order to use Vue, we need to install the vite vue plugin. Open your docker container called laravel-vue-laravel.test-1. This was the name of the project that I created. Go into the terminal. You can do this through your terminal, but I like doing it through the container since I can be sure that the correct versions are installed and I don’t have to worry about them on my computer.

Type the following command:

npm i vue@next

After that’s installed, run one more command to install the vue plugin:

npm i @vitejs/plugin-vue

If you get an error, you may need to run a command with the version:

npm i @vitejs/plugin-vue@3

vite.config.js

The vite.config.js file in your main directory needs to be modified. We’ll need to import Vue from our plugin and register it under plugins. You’ll probably see a file that looks like this:

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,
        }),
    ],
});

The file should look like this after you add all of the necessary code.

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import Vue from '@vitejs/plugin-vue';

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

resources/js/App.vue

Time to create the App.vue file. You can name it whatever you’d like as long as you know this is the entry point. I’ll start with a simple file that contains an h1 tag.

<template>
    <h1>Welcome Page from Vue</h1>
</template>

<script>
export default {
    name: 'App',
    components: {},
}
</script>

<style>

</style>

resources/js/app.js

Next, we need to modify our app.js file. It’s currently importing bootstrap.js from the same directory, but we need for it to actually import our App.vue. We’ll also need createApp from vue so that we can mount the content onto #app id within resources/views/welcome.blade.php. Your resources/js/app.js file should look like this.

import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

Renaming welcome.blade.php

I normally like to change the name from welcome.blade.php to index.blade.php. This also requires that you change the route in your route file, routes/web.php, to point to index.

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('index');
});

Including app.js in index.blade.php

The last modification to get this to work is to include the app.js file in index.blade.php. We can do this vith vite.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">

        @vite(['resources/js/app.js'])
    </head>
    <body class="antialiased">
        <div id="app"></div>
    </body>
</html>

Make sure it works

Go back to your container and run npm run dev. Visit your application in your browser, http://localhost or http://0.0.0.0, and see the Vue application running.

Installing Tailwind

We don’t want to stop here. We need to install Tailwind as well. The Tailwind website gives us really good instructions on how to do this.

Go back to your Docker container. If npm run dev is still running, hit CTRL+C to stop it. Execute the following commands:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

tailwind.config.js

Once complete, go back to your editor and open the newly created tailwind.config.js file that’s located in your root directory.

Modify the content section in the modeule.exports. Your file should look like this.

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./resources/**/*.blade.php",
    "./resources/**/*.js",
    "./resources/**/*.vue",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

resources/css/app.css

Tailwind also needs to be added to our app.css file.

@tailwind base;
@tailwind components;
@tailwind utilities;

Include app.css in index.blade.php

Finally, we need to include the app.css file in our index.blade.php file. We can do that with vite again.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">

        @vite(['resources/js/app.js', 'resources/css/app.css'])
    </head>
    <body class="antialiased">
        <div id="app"></div>
    </body>
</html>

Make sure it works

Go back to your container and run npm run dev. Visit your application in your browser, http://localhost or http://0.0.0.0, and see the Vue application running with Tailwind installed now.

Taking the Vue Application for a Spin

Let’s make a components directory within resources/js/. Once created, make a new file called Header.vue.

We’ll move our Welcome Page from Vue header from App.vue to Header.vue. We can also add some scoped styling to the h1 tag. To make sure that Tailwind works, we can add a p-4 class to our h1 tag.

<template>
    <h1 class="p-4">Welcome Page from Vue</h1>
</template>

<script>
export default {
    name: 'Header',
}
</script>

<style scoped>
    h1 {
        background-color: cornflowerblue;
        color: white;
    }
</style>

Modify App.vue to include the Header.vue component.

<template>
    <Header />
</template>

<script>
import Header from './components/Header.vue';

export default {
    name: 'App',
    components: {
        Header,
    },
}
</script>

<style>

</style>
Make sure that npm run dev is active and refresh your page. You’ll see it functioning properly.

Installing Vue Router

Let’s finish this by adding the vue-router. We’ll need to install the dependency first. Go to the Docker container and stop the application from running (CTRL+C). Install vue-router dependency with the following command:

npm install vue-router

You can check your package.json file to make sure all of your dependencies are added.

{
    "private": true,
    "scripts": {
        "dev": "vite",
        "build": "vite build"
    },
    "devDependencies": {
        "autoprefixer": "^10.4.13",
        "axios": "^1.1.2",
        "laravel-vite-plugin": "^0.7.0",
        "lodash": "^4.17.19",
        "postcss": "^8.4.20",
        "tailwindcss": "^3.2.4",
        "vite": "^3.0.0"
    },
    "dependencies": {
        "@vitejs/plugin-vue": "^3.2.0",
        "vue": "^3.2.36",
        "vue-router": "^4.1.6"
    }
}

web.php

We’re going to start running into some issues with the way our current web.php file is configured. Let’s get that out of the way first so that we don’t have to worry about it later.

<?php

use Illuminate\Support\Facades\Route;

Route::get('/{all}', function () {
    return view('index');
})->where("all", ".*");

Creating Home and About components

To test our routes, we’ll need to create a couple of components. I’m going to create two of the most common pages, Home and About.

<template>
    <div class="p-20">Home Page</div>
</template>

<script>
export default {
    name: 'Home',
}
</script>

<style scoped>
div {
    background-color: coral;
    color: white;
}
</style>
<template>
    <div class="p-20">About Page</div>
</template>

<script>
export default {
    name: 'Home',
}
</script>

<style scoped>
div {
    background-color: darkseagreen;
    color: white;
}
</style>

resources/js/router/index.js

Time to create our routes file. This will process all of our routes instead of web.php. For this file, we need to:

  • import createRouter and createWebHistory from vue-router
  • import any page component that we need to define a route to, like Home and About
  • create our routes constant and bind the component to it
  • create our router and bind history and routes to it
  • export router
import {createRouter, createWebHistory } from "vue-router";
import Home from "../components/Home.vue";
import About from "../components/About.vue"

const routes = [
    {
        path: "/",
        name: "home",
        component: Home,
    },
    {
        path: "/about",
        name: "about",
        component: About,
    },
];

const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes,
});

export default router;

resources/js/app.js

The exported router now needs to be imported. It needs to be imported into our app.js file. Once imported, we need to use it. Add the use(router) function before we mount our app.

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router/index";

createApp(App)
    .use(router)
    .mount("#app");

resources/js/App.vue

Finally, we need to modify the App.vue file so that it contains the contents that our router file returns. We are going to add <router-view /> directly underneath our <Header />.

<template>
    <Header />
    <router-view />
</template>

<script>
import Header from './components/Header.vue';

export default {
    name: 'App',
    components: {
        Header,
    },
}
</script>

<style>

</style>

Take the full app for a spin

Go back to your container and run npm run dev. Visit your application in your browser, http://localhost or http://0.0.0.0, and see the Vue application running with Tailwind and Vue-Router.

The main route, (/), will return the Hom

Going to the about route, (/about), will return the About component.

I’m going to add a couple of links to the header so that we can easily switch between the pages.

<template>
    <h1 class="p-4">Welcome Page from Vue</h1>
    <div class="p-4">
        <router-link to="/">Home</router-link> |
        <router-link to="/about">About</router-link>
    </div>
</template>

<script>
export default {
    name: 'Header',
}
</script>

<style scoped>
    h1, div {
        background-color: cornflowerblue;
        color: white;
    }
</style>

We can now click between the two pages. Have fun.

Laravel Series

Continue your Laravel Learning.

Laravel 9.x with Vue, Tailwind, and Vue-Router

Elevate your Laravel apps with Vue, Tailwind, and Vue Router

Laravel — P9.x – Vue,Tailwind, Vue-Router

In this guide, discover how to integrate Laravel 9.x with Vue, Tailwind, and Vue Router to build modern, responsive web applications. Streamline your front-end development with utility-first CSS, create modular components, and power seamless navigation across your single-page application.

Leave a Reply