DEV Community

Cover image for Using Vue in Laravel Without Inertia
Rafli Zocky
Rafli Zocky

Posted on • Originally published at Medium on

Using Vue in Laravel Without Inertia

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
Enter fullscreen mode Exit fullscreen mode

Steps

  • Installation
# laravel
laravel new example-app

# vue
npm install vue
npm install @vitejs/plugin-vue --save-dev
Enter fullscreen mode Exit fullscreen mode
  • 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(),
    ],
});
Enter fullscreen mode Exit fullscreen mode
  • 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")
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • Run
# start your web server, and then:

npm run dev
Enter fullscreen mode Exit fullscreen mode
  • Controller
# example

public function index()
{
    return view('app', [
        'page' => 'componentsname',
        'props' => [
            'title' => 'page title',
            'constant' => ['type' => 'monthly']
        ]
    ]);
}
Enter fullscreen mode Exit fullscreen mode

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)