Indíce de contenidos
Introducción
En esta publicación, abordaremos todo lo que necesitas saber para establecer un proyecto utilizando Laravel 10, Vue 3 y Vite. Exploraremos desde la fase inicial de la creación del proyecto en Composer hasta la implementación de Vue route y la resolución de posibles problemas que puedan surgir en el proceso.
Instalación
Para iniciar el proyecto, la primera tarea será generar el proyecto en Laravel, y para lograrlo, utilizaremos el siguiente comando.
php composer.phar create-project laravel/laravel laravel10-y-vue3
Este comando nos creara un proyecto con Laravel en la carpeta laravel10-y-vue3
una vez que la instalación haya terminado entraremos a la carpeta que se nos creó.
cd laravel10-y-vue3
y ejecutaremos el siguiente comando dentro del proyecto.
npm install
Este comando instalara las dependencias del package.json, laravel 10 por defecto incluye las siguientes dependencias en el package.json
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.8.0",
"vite": "^4.0.0"
}
}
Por último, deberemos de instalar las siguientes dependencias
npm install --save-dev vue
npm install --save-dev vue-loader
npm install --save-dev @vitejs/plugin-vue
Estas dependencias son para tener vue. vue-loader que se encargar de interpretar los archivos .vue y @vitejs/plugin-vue que nos ayudara a que vue se integre con vite
Configuración
Para comenzar a configurar el proyecto primero debemos de irnos a nuestro archivo vite.config.js y le añadimos las siguientes líneas.
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,
}),
],
});
Ahora creamos el siguiente archivo en /resources/js/Components/App.vue y colocaremos lo siguiente
<template>
<div>
Hola desde App.vue
</div>
</template>
<script>
export default {
data: () => ({
}),
};
</script>
Después nuestro archivo /resources/js/app.js debería quedar de la siguiente forma
import './bootstrap';
import { createApp } from 'vue'
import App from './Components/App.vue'
const app = createApp(App);
app.mount('#app')
Y crearemos el archivo blade /resources/views/vue.blade.php
<!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>Document</title>
@vite('resources/css/app.css')
</head>
<body>
<div id="app">
</div>
@vite('resources/js/app.js')
</body>
</html>
Ahora añadiremos la siguiente ruta en el archivo /routes/web.php.
Route::get('/inicio', fn() => view('vue'));
Y en diferentes terminales correremos los siguientes comandos, uno es para iniciar el servidor php y el otro es para que vite trate los archivos js y los sirva a la página local
php artisan serve
npm run dev
y tendríamos que ver lo siguiente

si todo salió bien hasta aquí y nos dirigimos a http://localhost:8000/inicio, nos debería mostrar lo siguiente

Hasta aquí ya tenemos funcionando vue con laravel, pero solo la página de /inicio tendrá vue, si queremos que haya otra página con otro componente vue tendríamos que crear otro archivo app.js con otro nombre y crear otra vista blade para este nuevo app.js, pero esto no es muy optimo si queremos crear una página con múltiples vistas, por lo que ahora veremos como instalar Vue Router
Instalar Vue Router
Comenzaremos ejecutando el siguiente comando que nos instalará la última versión de Vue Router, Cuando se hizo este post la versión fue la 4.2
npm install --save-dev vue-router
Y añadiremos los siguientes componentes
<template>
<!-- /resources/js/Components/Inicio.vue -->
<div>
<h1>Hola desde inicio</h1>
</div>
</template>
<script>
export default {
}
</script>
<template>
<!-- /resources/js/Components/Nosotros.vue -->
<div>
<h1>Hola desde nosotros</h1>
</div>
</template>
<script>
export default {
}
</script>
Modificaremos el archivo App.vue
<template>
<div>
<header>
<nav>
<ul>
<li>
<router-link to="/inicio">Inicio</router-link>
</li>
<li>
<router-link to="/nosotros">Nosotros</router-link>
</li>
</ul>
</nav>
</header>
<main>
<router-view></router-view>
</main>
</div>
</template>
<script>
export default {
data: () => ({}),
};
</script>
Y crearemos el siguiente archivo /resources/js/router.js, con el siguiente contenido
import { createRouter, createWebHistory } from "vue-router";
import Inicio from "./components/Inicio.vue";
import Nosotros from "./components/Nosotros.vue";
const routes = [
{ path: "/inicio", component: Inicio },
{ path: "/nosotros", component: Nosotros },
];
const history = createWebHistory();
const router = createRouter({
history,
routes,
});
export default router;
En nuestro archivo /resources/js/app.js añadiremos las siguientes líneas, que nos ayudara a que Vue pueda usar Vue Router
import './bootstrap';
import { createApp } from 'vue';
import App from './Components/App.vue';
import router from "./router";
const app = createApp(App);
app.use(router);
app.mount('#app');
Y en el web.php quitamos la ruta que habíamos creado previamente y añadiremos la siguiente ruta, de tal forma que nuestro archivo web.php debe quedar así
<?php
use Illuminate\Support\Facades\Route;
Route::get('/{page}', function () {
return view('vue');
});
Con esto tanto si nos dirigimos a http://localhost:8000/inicio, y a http://localhost:8000/nosotros nos debe mostrar su componente correspondiente.

La primera vez que se accede a la página se descargaran todos los archivos necesarios para el funcionamiento de la página como si fuera una SPA

Ya una vez que se descargó la página si y solo si el usuario da clic en un <router-link>
o por medio de la API de Vue route this.$router.push().
Vue route se encargará del cambio de página y mostrar el componente correcto con respeto las rutas que añadimos en el routes.js

En caso contrario si el usuario da clic en un <a>
o cambiamos de página por medio de windows.location.href = "https://localhost:8000/nosotros"
la petición se volverá a mandar al servidor afectando en rendimiento de nuestra página

Cosas importantes
Error 404
Algo importante a considerar es que si dejamos la ruta como se mencionó anteriormente
<?php
use Illuminate\Support\Facades\Route;
/* ESTA RUTA */
Route::get('/{page}', function () {
return view('vue');
});
Y por ejemplo, accedemos a la siguiente ruta http://localhost:8000/tienda, nos devolverá lo siguiente.

y si seguimos con cualquier otro valor en la ruta nos seguirá mostrando lo mismo, esto es incorrecto ya que nos debería de indicar que esta página no existe, para esto debemos de añadir un par de líneas extra a nuestro router.js
import { createRouter, createWebHistory } from "vue-router";
import Inicio from "./components/Inicio.vue";
import Nosotros from "./components/Nosotros.vue";
import NotFound from "./components/NotFound.vue";
const routes = [
{ path: "/inicio", component: Inicio },
{ path: "/nosotros", component: Nosotros },
{ path: "/:pathMatch(.*)*", component: NotFound },
];
const history = createWebHistory();
const router = createRouter({
history,
routes,
});
export default router;
Y crear el componente NotFound.vue
<template>
<!-- /resources/js/Components/NotFound.vue -->
<div>
<h1>No se encontro la pagina 404</h1>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
Ahora si accedemos a http://localhost:8000/tienda ya nos debería mostrar lo siguiente

Si bien esto es visual, ya que internamente el servidor nos sigue devolviendo el código 200. Para solucionar esto hay dos opciones que yo recomiendo
Crear las rutas en Laravel y mostrar la vista 404 de Laravel
Lo primero por hacer es remplazar la ruta que creamos por las siguientes rutas
<?php
use Illuminate\Support\Facades\Route;
Route::get('/inicio', fn() => view('vue'));
Route::get('/nosotros', fn() => view('vue'));
De esta manera siempre y cuando una ruta no exista en Laravel nos mostrara la vista 404 que trae por defecto Laravel.

Personalizando la vista 404 de Laravel con nuestro componente de Vue
Para esto debemos de crear la vista /resources/views/errors/404.blade.php es importante que sea en esa ruta ya que desde ahí Laravel tomara la vista cuando una ruta no se encuentre, y le pondremos lo siguiente a la vista
@include('vue')
De esta manera ya no nos mostrará la vista por defecto de Laravel y nos mostrará nuestro componente de NotFound.vue y la pagina devolverá el estatus 404, de esta manera el impacto en el SEO será menor ya que los buscadores les estará llegando el estatus correcto

Rutas con más niveles
Si tu deseo es crear rutas con más de una diagonal, también es posible. Partiendo de que en el punto anterior se indica la mejor manera de añadir las rutas para no tener un impacto en el SEO por el estatus 404
Lo único que haría falta seria modificar nuestro archivo web.php y router.js
<?php
use Illuminate\Support\Facades\Route;
/* web.php */
Route::get('/inicio/usuarios', fn() => view('vue'));
Route::get('/nosotros', fn() => view('vue'));
/* router.js */
import { createRouter, createWebHistory } from "vue-router";
import Inicio from "./components/Inicio.vue";
import Nosotros from "./components/Nosotros.vue";
import NotFound from "./components/NotFound.vue";
const routes = [
{ path: "/inicio/usuarios", component: Inicio },
{ path: "/nosotros", component: Nosotros },
{ path: "/:pathMatch(.*)*", component: NotFound },
];
const history = createWebHistory();
const router = createRouter({
history,
routes,
});
export default router;
de este modo ya nos mostrara el componente de Inicio.vue

Rutas con parametros
Si queremos que nuestra ruta tengo la posibilidad de aceptar parámetros tenemos que cambiar los siguientes archivos
<?php
use Illuminate\Support\Facades\Route;
/* web.php */
Route::get('/inicio/{usuario}', fn() => view('vue'));
Route::get('/nosotros', fn() => view('vue'));
/* router.js */
import { createRouter, createWebHistory } from "vue-router";
import Inicio from "./components/Inicio.vue";
import Nosotros from "./components/Nosotros.vue";
import NotFound from "./components/NotFound.vue";
const routes = [
{ path: "/inicio/:usuario", component: Inicio },
{ path: "/nosotros", component: Nosotros },
{ path: "/:pathMatch(.*)*", component: NotFound },
];
const history = createWebHistory();
const router = createRouter({
history,
routes,
});
export default router;
<template>
<!-- /resources/js/Components/Inicio.vue -->
<div>
<h1>Hola desde el inicio del {{ usuario }}</h1>
</div>
</template>
<script>
export default {
computed: {
usuario(){
return this.$route.params.usuario;
}
}
}
</script>
Con estos cambios podemos ver que siempre que se cambie la url cambiara el texto del componente Inicio.vue

Pasar datos entre Laravel y Vue
Lamentablemente no hay una manera fácil de pasar datos. Por lo que siempre necesitaremos usar AJAX para traer datos de nuestro backend a Vue.
Para realizar esto tendremos que modificar los siguientes archivos
<?php
use Illuminate\Support\Facades\Route;
/* web.php */
Route::get('/datos/usuarios/{usuario}', function ($usuario) {
return response()->json([
'datos' => match ($usuario) {
'usuario' => [
'nombre' => 'José Usuario'
],
'admin' => [
'nombre' => 'Manuel Admin'
],
'editor' => [
'nombre' => 'Sonia Editor'
],
'ejecutivo' => [
'nombre' => 'Diego Editor'
],
default => [
'nombre' => 'Usuario no registrado'
],
}
], 200);
});
Route::get('/inicio/{usuario}', fn() => view('vue'));
Route::get('/nosotros', fn() => view('vue'));
<template>
<!-- /resources/js/Components/Inicio.vue -->
<div>
<h1>Hola desde el inicio del {{ usuario }}</h1>
<p>
El nombre del usuario es: <strong>{{ nombreUsuario }}</strong>
</p>
</div>
</template>
<script>
export default {
computed: {
usuario() {
return this.$route.params.usuario;
},
},
data: () => ({
nombreUsuario: "",
}),
created() {
//Se ejecutara al crear el componente
this.obtenerUsuario();
},
methods: {
obtenerUsuario() {
const _this = this;
//Traera los datos desde el backend
axios.get(`/datos/usuarios/${this.usuario}`).then(function (res) {
_this.nombreUsuario = res.data.datos.nombre;
});
},
},
watch: {
usuario(newValue, oldValue) {
/*
Ayudara a actualizar si es que se cambia por la API de Vue Router
o por el componente de <router-link/>
*/
if (newValue != oldValue) {
this.obtenerUsuario();
}
},
},
};
</script>
Ya con esto nos actualizara el nombre del usuario que añadimos en la url

Continuar usando vistas de Blade
Si tienen un proyecto que ya tenga vistas blade, y requieras seguir usándolas o quisieras integrar otras vistas que solo dependan de blade. también es posible, solo te en cuenta que la ruta no debe existir con un componente Vue, por ejemplo
Añadiremos la siguiente ruta
Route::get('panel',function(){
return view('panel');
});
y crearemos la vista panel.blade.php
{{-- /resources/views/panel.blade.php --}}
<!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>Document</title>
</head>
<body>
<h1>Hola desde el panel sin VUE</h1>
</body>
</html>
</html>
Si vamos a la ruta http://localhost:8000/panel veremos que está funcionando sin problema

Lo bueno de esto es que se puede navegar entre las vistas que posean Vue y las que no, pero si hay que tener en cuenta lo siguiente
-
Si se va a navegar entre vistas que posean Vue, se debe hacer por medio del componente
<router-link/>
o la API de Vue Router, en caso contrario podríamos ver problemas de rendimiento en nuestra página -
Si vamos a navegar de una vista de que NO contiene Vue a una vista que SI contiene Vue, solo podremos hacerlo mediante la etiqueta
<a>
o mediantewindows.location.href
-
Si vamos a navegar de una vista que, SI contiene Vue a una vista que NO contiene Vue, debemos hacerlo mediante la etiqueta
<a>
o mediantewindows.location.href
ya que si lo hacemos con el<router-link/>
o con la API de Vue router, nos mandara al componente NotFound.vue
Conclusiones
Si bien en este artículo hemos explorado la óptima forma de establecer un proyecto utilizando Laravel 10, Vue 3 y Vite, con todas las características disponibles para la creación de tu página web, es posible que la gestión de las rutas en Laravel y las rutas en Vue Router pueda resultar un tanto compleja y difícil de mantener. Si así lo deseas, puedes mantener tu proyecto en este enfoque. Sin embargo, es importante señalar que la comunidad ya había identificado este problema, lo que llevó al desarrollo de InertialJS. Esta herramienta ha sido creada para facilitar la conexión entre Laravel y Vue de una manera más sencilla.
Te animo a que explores nuestro artículo que aborda cómo concebir un proyecto utilizando Laravel 10, Vue 3, Vite e InertialJs. En él encontrarás información detallada sobre cómo aprovechar esta combinación de tecnologías de manera efectiva.