starkovsky / laravel-vue-cli

Laravel 7 + Vue CLI 4 SPA (Vuex, Router, Test) Admin + Public builds
167 stars 58 forks source link

How do you get data from laravel to vue-cli project without AJAX? #119

Closed kevnk closed 4 years ago

kevnk commented 4 years ago

If I wanted to get session or csrf token from Laravel into my vue-cli project, how would you do that without relying on ajax requests?

kevnk commented 4 years ago

Here's how I solved it. It uses some concepts from Laravel Spark (mainly, using a global javascript variable to hold data from Laravel that your vue app can use).

FrontendController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class FrontendController extends Controller
{
    // For admin application
    public function admin()
    {
        return view('admin', ['scriptVariables' => $this->scriptVariables(Auth::user())]);
    }
    // For public application
    public function app()
    {
        return view('app', ['scriptVariables' => $this->scriptVariables()]);
    }

    public function scriptVariables($user = null)
    {
        return [
            'user' => $user,
            '_token' => csrf_token(),
            '_session' => session()->getId(),
        ];
    }
}

/routes/web.php

// Local dev only
if (App::environment('local')) {
    Route::get('/json', function() {
        $data = app('App\Http\Controllers\FrontendController')->scriptVariables(Auth::user());
        $timestamp = now('America/Chicago')->format('Y-m-d');
        Storage::disk('public')->put("app-$timestamp.json", collect($data)->toJson());
        return $data;
    });
}

/resources/frontend/app/public/index.html

<html>
    <head>
    <!-- // ... -->
    <script>
    <% if (NODE_ENV !== 'development') { %>
        window.App = @json(array_merge($scriptVariables, []));
    <% } %>
    </script>
    </head>
    <body>
    <div id="app">
        <% if (NODE_ENV === 'development') { %>
            Fetching data...
        <% } %>
    </div>
    <!-- // ... -->
    </body>
</html>

/resources/frontend/app/.env.development

VUE_APP_JSON_URL=http://laravel.test/json

Rename main.js to vm.js

mv /resources/frontend/app/main.js /resources/frontend/app/vm.js

(new file) /resources/frontend/app/main.js

import axios from 'axios';

const initApp = () => import(/* webpackChunkName: "vm" */ './vm.js');

if (process.env.NODE_ENV === 'development') {
  try {
    let date = new Date();
    let Y = date.getFullYear();
    let m = date.getMonth() + 1 + '';
    m = m.length === 1 ? '0' + m : m;
    let d = date.getDate() + '';
    d = d.length === 1 ? '0' + d : d;
    let timestamp = `${Y}-${m}-${d}`;
    window.App = require(`../../../storage/app/public/app-${timestamp}.json`);
    initApp();
  } catch (err) {
    axios
      .get(process.env.VUE_APP_JSON_URL)
      .then(({ data }) => {
        window.App = data;
        initApp();
      })
      .catch(alert);
  }
} else {
  initApp();
}

Now, anywhere in your app (eg vuex store, etc.), you have access to window.App variable.

What's this doing?

On your local environment only, we're creating a /json route that will return the same data you'll be getting in production. It's saving this json response also, so if you need to test with data on your network during development (eg. http://192.168.0.15:8080/ from vue serve), it can.