Navigating on Vue with server-side rendering and Laravel

Currently, I am delving into Vue and facing a challenge setting it up as the complete front-end with Laravel. In my current setup, I have created a personal blog for testing purposes using Laravel with Blade engine and incorporating some Vue components which seems to function correctly.

Now, I want to take it a step further by eliminating Blade entirely and utilizing Laravel solely as an API backend while configuring Vue as the full front end with Server-Side Rendering (SSR). The basic setup is working; I can call Vue and render it using SSR with either Node or PHPv8. However, the issue I am encountering lies in the routing system. Unlike Blade where I could achieve the desired result by employing a default layout as the master and importing it for every post, page, blog, etc...

For instance:

resources/views/layouts/master.blade

<!DOCTYPE html>
<html dir="ltr" lang="{{ app()->getLocale() }}">

    <head>
        @include('partials._head')
    </head>

    @if(View::hasSection('body')) {{-- Load Custom Body --}}
        <body @section('body')>
    @else
        <body>
    @endif

        @yield('content')

        @include ('partials._javascripts')

        @section('scripts')
    </body>

</html>

This structure allows me to dynamically load head per page/post, dynamic content, essential JavaScript libraries (Bootstrap, Vue, FontAwesome, etc...), and custom 'scripts' per page/posts.

I am utilizing the library described at:

https://github.com/spatie/laravel-server-side-rendering

Although I have successfully implemented SSR with node or PHPv8, the vue-router does not seem to call the correct page. My setup includes:

resources/assets/js/app.js

import Vue from 'vue';
import App from './layouts/App';
import axios from 'axios';
import store from './store';
import router from './router';
import navbar from './components/navbar';
import posts from './components/posts';
import sidebar from './components/sidebar';
import footer from './components/footer';
import BlogIndex from './views/blog/BlogIndex';



export default new Vue({
    store,
    router,
    navbar,
    posts,
    sidebar,
    footer,
    BlogIndex,
    render: h => h(App),
});

resources/assets/js/entry-client.js

import app from './app';

app.$mount('#app');

resources/assets/js/entry-server.js

import app from './app';
import renderVueComponentToString from 'vue-server-renderer/basic';

app.$router.push(context.url);

renderVueComponentToString(app, (err, html) => {
    if (err) {
        throw new Error(err);
    }
    dispatch(html);
});

resources/assets/js/router.js

// router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from './components/Home';
import BlogIndex from './views/blog/BlogIndex';

Vue.use(VueRouter);

const routes = [
    { path: '/', name: 'home', component: Home },
    { path: '/blog', name: 'blog', component: BlogIndex },
];

export default new VueRouter({
    mode: 'history',
    routes,
});

resources/assets/js/store.js

import Vue from 'vue';
import uniq from 'lodash/uniq';
import Vuex, { Store } from 'vuex';

Vue.use(Vuex);

export default new Store({
    state: {
    },

    getters: {
    },

    mutations: {
    },
});

resources/assets/js/views/blog/BlogIndex.vue

<template>
    <div class="container">
        <navbar></navbar>
        <posts></posts>
        <sidebar></sidebar>
        <footer></footer>
    </div>
</template>



<script>

    export default {
        name: "BlogIndex",
        components: {
        }
    }
</script>

<style scoped>

</style>

app/Http/Controllers/VueSSRController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Routing\Route;

class VueSSRController extends Controller
{

    public function __invoke()
    {
        return view('layouts.vue');
    }

}

resources/views/layouts/vue.blade.php

<!DOCTYPE html>
<html dir="ltr" lang="{{ app()->getLocale() }}">

    <head>
        @section('extrajavascripts'){{ asset('js/scripts.min.js') }}@endsection
        @include('partials._head')
    </head>

    @if(View::hasSection('body')) {{-- Load Custom Body --}}
    <body @section('body')>
    @else
    <body>
    @endif

        {{-- Begin of Vue SSR --}}
        {!! ssr('resources/assets/js/server_bundle.min.js')
            // Share the packages with the server script through context
            //->context('packages', $packages)
            // If ssr fails, we need a container to render the app client-side
            ->fallback('<div id="app"></div>')
            ->render() !!}
        {{-- End of Vue SSR --}}

        @include ('partials._javascripts')

        @section('scripts')
        @show

    </body>

</html>

/resources/assets/js/layouts/App.vue

<template>
    <div id ="app">
        {{ message }}
    </div>
</template>

<script>
    export default {
        name: "App",
        data() {
            return {
                message: 'SSR working.'
            }
        }
    }
</script>

<style scoped>

</style>

While the SSR functionality works smoothly, the problem arises when the resources/assets/js/router.js does not trigger the loading of the resources/assets/js/views/blog/BlogIndex.vue. Even though the URL "/blog" functions properly, the rendered component is consistently /resources/assets/js/layouts/App.vue.

I would greatly appreciate any guidance on what might be missing in my setup!

Thank you in advance!!!

Answer №1

To enable routing, simply insert

<router-view></router-view>
wherever you wish the router to display content. In this scenario, I recommend positioning it below {{message}} in the App.vue file.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you modify the value of the link identified as "#showCities" based on the city that is clicked on?

There is a link called "All Country" that, when clicked, opens a modal displaying a list of cities: <a class="city" id="showCities" data-toggle="modal" data-target="#modal2" href="">All Country</a> The modal lists all the cities associated wi ...

Creating a Fresh Global Scope in Laravel

Encountering an issue while trying to add a new global scope in Laravel 5.7: Error message: Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_PARSE) syntax error, unexpected 'static' (T_STATIC) < ...

How to Conceal Attributes on a Global Scale When Converting Arrays or JSON in Laravel?

At times, you might want to restrict certain attributes from being included in your model's array or JSON representation, such as passwords. In order to achieve this, you can add a hidden property definition to your model: class User extends Model { ...

Laravel Artisan custom command cannot be executed via a cron job

I have created custom Artisan commands that work perfectly when run locally or on my production server while SSH'd in, but for some reason, they are not accessible from any cron jobs. I have even attempted to execute them using the same user as the cr ...

Creating a text file and JSON in Laravel 4 framework: A step-by-step guide

Hey there! I have a simple question that I haven't been able to find an answer to. I'm looking to generate a .txt file using Laravel 4 and upload it to my server similar to how PHP does. Additionally, I need to create a JSON file with Laravel 4 ...

What is the best way to handle identical routes within two separate route groups in Blade?

I have set up two resource controllers within separate route groups - one for users and one for admins. Route::group([ 'prefix' => 'dashboard', "middleware" => 'auth', "namespace" => 'U ...

What is the process for embedding a YouTube channel URL in PHP code?

When attempting to embed a YouTube channel URL on my php page, I encountered the following error: Refused to display 'https://www.youtube.com/channel/fakecode' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'. ...

Error code 405: The POST method is not compatible with submitting multiple forms using JavaScript code simultaneously

Having multiple forms on a single page that are all submitted using the same JavaScript code presents some challenges. <form class="form" id="cancelchallenge1" method="POST" action="{{action('ChallengeController@cancelChallenge')}}"> <i ...

Localhost is causing issues with Laravel in retrieving webfonts

I was trying to incorporate font-awesome into my Laravel project, but encountered a strange error. When I run the project, the following error appears in the console: GET http://localhost/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2?5 ...

Encountering challenges while integrating Angular with a Laravel forum creation project

Currently, I am working on building a forum application that involves users, posts, and comments using Laravel. However, the next step in my project requires integrating Angular, which is new territory for me and I'm not sure where to start. I have a ...

Failing to clear the cache after deployment can lead to issues

I am facing a situation in my Laravel application where I need to update the code from GitHub without clearing the cache every time. Typically, I use the following command to pull the latest changes: git pull origin staging However, whenever I do this an ...

Using headers in the fetch api results in a 405 Method Not Allowed error

I am facing an issue while attempting to make an ajax request using fetch. The response I receive is a 405 (Method Not Allowed) error. Here is how I am trying to execute it: fetch(url, { method: 'get', headers: { 'Game-Toke ...

"Embracing Micro-frontends: Building dynamic web applications using a variety of frontend

I am currently facing a software architecture dilemma. My extensive monolithic web application is built using PHP and backbone js, but I am eager to integrate a new front-end framework like react/vue. The question arises about the best approach to tackle t ...

Verifying Emails using CRUD API in Laravel 9

I have a question about email verification using Laravel. There are specific server considerations: The client consumes an API that only needs to return JSON responses, not views via HTTP. Therefore, all routes are defined in api.php instead of web.php. ...

Having an issue with my Vue page where it is attempting to send a request twice. My tech stack includes inertia, Laravel, and

<template> <app-layout title="Dashboard"> <template #header> <h2 class="h4 font-weight-bold">Create</h2> </template> <div class="container mt-5 text-gray-300"> ...

Unable to verify identity using spa

My API is running on the URL: https://example.com, and my vue.js app is running on: https://app.example.com. I have configured the .env file as follows: SESSION_DOMAIN=.example.com SANCTUM_STATEFUL_DOMAINS=https://app.example.com The axios configuration i ...

The ID attribute of Laravel blade file input is missing

Within my blade file, I have the following line of code: {!! Form::file('motivation', old('motivation'), ['id' => 'inputGroupMotivation', 'class' => 'custom-file-input']) !!} Although I ha ...

How can I format time display as shown in Laravel 5.2?

I am currently working with Laravel 5.2 and I would like to display the creation time of articles in a specific format: created_at displaying in 1 day today 2-10 days ...

Attempting to include additional fields in the registration form in Laravel may not function as expected

I've been attempting to include additional fields in my registration form within Laravel, but unfortunately, it's not functioning as expected. Despite receiving no errors, the page simply reloads without saving any data to the database. Initiall ...

The information transmitted from the Laravel controller is not syncing with the Vue variable as expected

I've been working on a web app with a dashboard using Laravel and Vue. While passing data from the controller to the Vue file, the data is received correctly. However, when I try to set it to a Vue variable, the value does not update in the variable. ...