We can use inertia.js, but sometimes we just need to keep it simple. This also works for React and others.
Folder Structure
# only an example
resources
├ js
│ ├ app.js
│ ├ App.vue
│ ├ pages
│ │ └ Dashboard.vue
│ ├ components
│ │ └ ui
│ └ layouts
└ views
└ app.blade.php
# Flow
Laravel route
↓
controller returns Blade
↓
Blade sets PAGE + PROPS
↓
Vue loads correct page component
↓
component receives props
Steps
- Installation
# laravel
laravel new example-app
# vue
npm install vue
npm install @vitejs/plugin-vue --save-dev
- Vite
# vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
vue(),
],
});
- Entry
# resources\js\app.js
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
# 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>
- Connect
# resources\views\layouts\app.blade.php
<!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>
- Run
# start your web server, and then:
npm run dev
- Controller
# example
public function index()
{
return view('app', [
'page' => 'componentsname',
'props' => [
'title' => 'page title',
'constant' => ['type' => 'monthly']
]
]);
}
Need help building your app? I’m available for freelance web & Android development — raflizocky.netlify.app
☕ Support my writing: paypal.me/raflizocky · saweria.co/raflizocky
Top comments (0)