Setting up a project in Laravel with Vue 3 in Mix and Vite.js

Video thumbnail

Laravel and Vue.js are one of the most powerful combinations in modern web development. Laravel, as a PHP backend framework, offers robustness and structure; while Vue, from the frontend, provides dynamism and a reactive architecture that improves the user experience. Integrating both is not only possible, but also simple if you understand how their layers connect.

The scheme we saw earlier for handling user preferences from a JSON field is ideal when using Vue, since internally using JavaScript, JSON is the best ally.

In this article, I'll show you how to integrate Vue 3 into Laravel using Vite (the current standard) and also Laravel Mix, for those working with older versions. Additionally, I'll share how I modularized my components in a real project to keep them reusable and scalable.

Why Use Vue with Laravel?

Vue.js and Laravel naturally complement each other. Laravel uses Node.js for asset compilation, which allows the incorporation of modern client-side frameworks without complications. Vue integrates perfectly thanks to its simplicity and tools like Laravel Vite Plugin or Laravel Mix.

In my case, this integration allowed me to build more interactive applications without abandoning the PHP ecosystem. For example, I managed to reuse the same Vue component in several sections of my application (courses, books, and packs) without duplicating code.

Prerequisites and Installation

Before starting, make sure you have:

  • Laravel 9.x or higher
  • Node.js and npm installed.
  • A development environment with PHP 8+.

Laravel Mix or Vite

If you are using Laravel Mix in your Laravel project, these are the steps you need to follow; we are going to configure Vue 3 in a Laravel 9 project. First, let's install the dependencies:

Install Vue and dependencies

$ npm install --save vue@next
$ npm install vue-loader
  • Vue next refers to Vue 3.
  • Vue Loader is what allows Vue files to be translated into JavaScript.

As of Laravel 9.x, the framework uses Vite by default, but if you work with older versions, Laravel Mix is still valid.

Vue 3 is installed with vue@next, and vue-loader is responsible for translating .vue components into native JavaScript.

Configuration of the webpack.mix.js file (mix)

mix.js('resources/js/app.js', 'public/js')
.js('resources/js/vue/main.js', 'public/js')
.vue()
.postCss('resources/css/app.css', 'public/css', [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
]);

Base project structure and mounting point

The next thing we are going to do is create a file with the Vue 3 instance, with which we can create components and more:

resources/js/vue/main.js:

import { createApp } from "vue";
import App from "./App.vue"
const app = createApp(App)
app.mount("#app")
Creamos el componente principal, el llamado App.vue:
resources/js/vue/App.vue:
<template>
    <div>
        <h1>Principal</h1>
        <list/>
    </div>
</template>
<script>
import List from "./componets/List";
export default {
    components:{
        List
    }
}
</script>

And use the @vite directive in Blade:

@vite('resources/js/vue/main.js')
<div id="app"></div>

And an example component, the list one:

resources/js/vue/components/List.vue:

<template>
  <div>
    <h1>Post List</h1>
  </div>
</template>

And with this, we have installed and configured Vue in a Laravel project; the next thing we are going to do is create a page from blade, to consume the Vue application:

Also note that we use the .vue function which allows the transpilation of .vue files into a js file; with this, the next thing we need is to create a page that we can use to display the Vue application:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue</title>
</head>
<body>    
    <div id="app"></div>
    <script src="{{ asset('js/main.js') }}"></script>
</body>
</html>
Y su ruta:
// web.php
Route::get('/vue', function () {
    return view('vue');
});

Add Vue 3 to the Laravel project (with Laravel Vite)

You have to follow these steps if you are developing a Laravel project that has the vite.config.js file.

We are going to add the Vue 3 dependencies to the Laravel project:

$ npm install --save vue@next
$ npm install vue-loader

vue@next is the current package to install vue 3, and vue-loader is simply the package that allows processing .vue files and generating an output file that the browser can understand. 

vue-loader is the loader for webpack that allows processing Vue components.

In addition to the previous packages, we have to install the Vue plugin with Vite:

$ npm install @vitejs/plugin-vue

And in the Vite configuration file, we add Vue:

vite.config.js

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue'
export default defineConfig({
    plugins: [
        vue(),
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
});

Now, we have the dependencies ready, let's configure the project; for this, we are going to create the necessary files, which are basically the same as those that exist in a project generated with the Vue Cli.

We will create some files in the resources folder whose structure and functionality we indicate below.

This first file would be to build the main Vue instance; remember that it is also the one we use to configure any other plugin.

resources/js/vue/main.js:

import { createApp } from "vue";
import App from "./App.vue"
const app = createApp(App)
app.mount("#app")

With this, upon entering the mentioned route we have:

App in vue
App in vue

 

Modularizing components and best practices

Video thumbnail

Here comes the part that makes the difference. Integrating Vue is easy; making it scalable and reusable is what distinguishes a professional project.

Using props and dynamic routes

In my experience, modularizing components using props and configurable routes is key. This way, I could use the same payment component for different resources (courses, books, or packs) simply by changing the input parameters.
For example:

<PaymentPlugin 
 :slug="slug" 
 :price="price" 
 :redirect="redirectRoute" 
/>

Polymorphic relationships and reusable components

On the backend side, I leveraged Laravel's polymorphic relationships to manage different models with the same payment structure. This allowed me to maintain common business logic without duplicating code.

In the database, the same Payment model can belong to a course, a book, or a pack thanks to Laravel's morphTo relationships. This way, Vue only needs to know what type of resource it is handling, and the backend takes care of the rest.

Real example: adaptable payment component

This approach allowed me to build a reusable payment plugin that:

  • Validates if the user is authenticated.
  • Applies dynamic coupons.
  • Manages payments with PayPal (and soon Stripe).
  • Offers additional features like "gift course" or "view for free".
  • Each behavior is activated or deactivated according to the received props, without touching the component's base code.

Displaying Vue components from Blade

Laravel and Vue coexist perfectly. It's enough to create a Blade view that acts as an entry point:

// routes/web.php
Route::get('/vue', function () {
 return view('vue');
});

And inside resources/views/vue.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Vue App</title>
</head>
<body>
 <div id="app"></div>
 @vite('resources/js/vue/main.js')
</body>
</html>

Common errors when integrating Vue and how to solve them

  • ❌ The component does not mount: check that the div's id matches that of app.mount("#app").
  • ⚙️ Dependency problems: make sure to use vue@next for Vue 3.
  • ⚡ Hot reload does not work: verify that refresh: true is active in vite.config.js.
  • Confusion between Mix and Vite: use Vite for Laravel 9+ and Mix only if you maintain older projects.

Conclusion and next steps

Integrating Vue 3 into Laravel is simpler than it seems, but doing it well means going beyond the basic tutorial.
In my case, modularizing each component and relying on Laravel's polymorphic relationships allowed me to scale my application without headaches, reusing code and maintaining project coherence.

If you have already managed to integrate Vue into your environment, the next step is to apply these best practices to maintain clean, reusable, and scalable code.

FAQs

Which is better: Laravel Mix or Vite for Vue?
Vite is the current standard since Laravel 9. It is faster and more modern than Mix.

Can I use Vue 2 in Laravel?
Yes, but it is recommended to migrate to Vue 3 for compatibility with Vite and long-term support.

How do I render a Vue component inside Blade?
You only need to create the div with id="app" and mount Vue onto it with createApp(App).mount("#app").

The next step is to learn how to use custom error pages.

I agree to receive announcements of interest about this Blog.

We're going to configure Vue 3 in a Laravel project using Node, and with this, take advantage of the entire Node ecosystem together with Laravel.

| 👤 Andrés Cruz

🇪🇸 En español