Integrating Vue.js in Laravel Without Inertia
Integrating Vue.js into a Laravel project doesn't always necessitate Inertia.js. Sometimes, simplicity is key, and this guide offers a straightforward method to achieve that.
Project Structure
Before diving into the setup, let's outline a typical folder structure to maintain organization and clarity:
resources
├ js
│ ├ app.js
│ ├ App.vue
│ ├ pages
│ │ └ Dashboard.vue
│ ├ components
│ │ └ ui
│ └ layouts
└ views
└ app.blade.php
Workflow Overview
The workflow for integrating Vue.js involves:
- Defining a Laravel route.
- Controller returns a Blade view.
- Blade passes PAGE and PROPS.
- Vue loads the appropriate page component.
- Components receive props dynamically.
Installation Steps
Setting Up Laravel and Vue
Start by creating a new Laravel project:
laravel new example-app
Next, install Vue.js and Vite plugin for Vue:
npm install vue
npm install @vitejs/plugin-vue --save-dev
Configuring Vite
Modify your vite.config.js file as follows:
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(),
],
});
Setting the Entry Point
In your resources/js/app.js file, configure the Vue app:
import { createApp, h } from 'vue';
import App from './App.vue';
const app = createApp({
render: () => h(App, {
page: window.PAGE,
props: window.PROPS
})
});
app.mount('#vue-app');
Root Component Setup
Create the root Vue component in resources/js/App.vue:
<script setup>
import { defineAsyncComponent } from 'vue';
import AppSidebar from './components/app-sidebar.vue';
const props = defineProps({
page: String,
props: Object
});
const pages = import.meta.glob('./pages/**/*.vue');
const loader = pages[`./pages/${props.page}.vue`];
const PageComponent = loader ? defineAsyncComponent(loader) : null;
</script>
<template>
<div class="flex min-h-screen">
<AppSidebar />
<main class="flex-1 p-6">
<component v-if="PageComponent" :is="PageComponent" v-bind="props.props" />
<div v-else>Page not found</div>
</main>
</div>
</template>
Connecting with Blade
In the resources/views/layouts/app.blade.php, integrate the Vue app:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<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">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name') }}</title>
<script>
window.PAGE = @json($page);
window.PROPS = @json($props);
window._USER = @json(auth()->user());
window.APP_NAME = @json(config('app.name'));
</script>
@vite(['resources/js/app.js'])
</head>
<body>
<div id="vue-app"></div>
</body>
</html>
Running Your Application
Start your server and run the development environment:
npm run dev
Controller Example
Here's a simple example of a controller function:
public function index()
{
return view('app', [
'page' => 'componentsname',
'props' => [
'title' => 'page title',
'constant' => ['type' => 'monthly']
]
]);
}
This setup allows for a seamless integration of Vue.js in Laravel projects without the complexity of Inertia.js.