I’ve been working on projects that use both Vue and Laravel for the last two to three years, and during the start of each’s development I have to ask myself “How am I going to pass my data from Laravel to Vue?”. This applies to both applications where the Vue frontend components are tightly coupled to Blade templates, as well as single-page applications running completely separate of the Laravel backend.
Here’s four different ways to get your data from one to the other.
Directly echo-ing into the data object or component prop
- Pro: Simple and straightforward
- Con: Has to be used with Vue apps that are embedded in Blade templates
Arguably the easiest way to move data from your Laravel application to a Vue frontend. Using either of the methods above you can just echo out JSON encoded data to be picked up by your app or its components.
The biggest downside to this however, is extensibility. Your JavaScript will need to be exposed directly in your template files so that the engine can render out your data. This shouldn’t be a problem if you’re using Vue to add some basic interactivity to a page or area of your Laravel site, but you’ll easily hit a wall trying to force data into packed scripts.
Using custom components and Laravel’s json
blade directive does allow you to move data into props easily. This method lets you to compartmentalize your Vue code, bundling your scripts with webpack or mix, while still being able to inject data directly into them.
Injecting items as global window properties
- Pro: Globally available across the entire Vue app and any other scripts
- Con: Can be messy and generally isn’t recommended for large data sets
While this might seem a little hack-y, adding in data to the window object easily allows you to create global variables that are accessible from any other script or component being used on your app. In the past, I’ve used this as a quick and dirty method of storing and accessing API base urls, public keys, specific model IDs, and a variety of other small data items that I’d need to use across my whole frontend.
There is a slight caveat with using this method though, and that’s how you access the data inside of Vue components. Inside of your template, you won’t be able to use something like the below, since Vue assumes the window object you’re trying to access will lie inside that same component:
// won't work
<template>
<div v-if="window.showSecretWindow">
<h1>This is a secret window, don't tell anyone!</h1>
</div>
</template>
Instead, you’ll need to use a computed method that returns the value:
// will work
<template>
<div v-if="showSecretWindow">
<h1>This is a secret window, don't tell anyone!</h1>
</div>
</template>
<script>
export default {
computed: {
showSecretWindow() {
return window.showSecretWindow;
}
}
}
</script>
If your use case for this method is smaller strings or numerical values and you’re using Laravel’s mix to compile your assets, things can actually get pretty simple. You can reference values from your .env
file in your JavaScript using the process.env object. For example, if I have API_DOMAIN=example.com
in my environment variables file, I can use process.env.API_DOMAIN
in my Vue component (or other JavaScript compiled with mix) to access that value.
Using an API with Laravel’s web middleware and CSRF tokens
- Pro: Easy to get started, perfect for Single Page Applications
- Con: Requires your frontend to be rendered by a blade template
For me, this solution has been the most straightforward way to get started in the Vue frontend + Laravel backend world. Out of the box, Laravel comes with two different files for routes, web.php
and api.php
. These are pulled in and mapped through the RouteServiceProvider.php
file in your app’s Providers directory. By default, the middleware for the web group is set to web, and the middleware for the api group is set to api.
Tracing this back to app/Http/Kernel.php
you’ll notice that around line 30 there’s the two groups mapped out in an array, with the web group containing things like sessions, cookie encryption, and CSRF token verification. Meanwhile, the api group just has a basic throttle and some bindings. If your goal is to simply pull in information to Vue through a basic, lightweight api, that doesn’t require authentication or post requests, then you can stop right here. Otherwise, a single modification can be made that’ll ensure complete compatibility with Vue in just a few seconds.
Back on the RouteServiceProvider
, swap out the api middleware in the mapApiRoutes
method for web. Why are we doing this, and what does it do? It enables the routes that we’re pulling in through our api to also contain any session variables and tokens that our app’s regular web routes would normally use. When these are called with axios or another async JavaScript http client, we’re able to use Auth::user() and other validation techniques in the backend that we wouldn’t be able to do with the default api.
The only caveat of this method is that you’ll have to render out your frontend using Laravel and a blade template. This way the framework can inject the necessary session tokens and variables into the request(s).
Using API calls authenticated by a JWT
- Pro: Most secure and decoupled option
- Con: Requires third-party package to be installed and configured
JSON Web Tokens are a secure, easy to use method of locking down access to your API endpoints and using Tymon’s jwt-auth package makes adding the functionality to a new or existing Laravel app an absolute no-brainer.
Getting this functionality installed and configured on your API takes a couple short steps:
From your app root, run
composer require tymon/jwt-auth
. There’s currently a transitionary period happening at the time of this article, so you may need to specify the version (e.g. 1.0.0-rc.5)If you’re in Laravel 5.4 and under, add the line
Tymon\JWTAuth\Providers\LaravelServiceProvider::class
, to your providers array in config/app.phpPublish the config file by running
php artisan vendor:publish
and choosing the jwt-auth packageRun
php artisan jwt:secret
to generate the key needed to sign your app’s tokens
After that’s complete, you’ll need to specify what routes in your application will be protected by and authenticated against JWTs. You can do this by using the built-in api auth middleware, or roll your own that looks for the token in the sent request. In your API’s login method, you’ll use the same auth()->attempt
method as a default Laravel app, except returned from it will be your JSON Web Token that you should pass back.
From there, your Vue app should store that token (in either LocalStorage or a Vuex store), and add it as an Authorization header in every outgoing request that requires it. Back on your Laravel app, you can use their token to reference the particular user making requests, passing back data that should be shown to just them.
If you’d like a more in-depth tutorial explaining how to install and integrate JWTs into your Laravel API, I’ve published a video and wrote a post about just that!
That’s it for now! If you have any questions or comments about the above, or want to just see helpful hints and industry news day-to-day, feel free to follow me on Twitter! In addition, if you’re looking for a super simple error and log monitoring service specifically for Laravel apps, I’ve built Larahawk. It’s currently in private beta and launching in October for $5/app/month.
Top comments (12)
2 things
Thanks a lot for pointing out the single quote ( number 1). I was almost already dismissing this post
Nice catches! I've wrote about #2 before, love using echo.
Nice article! I'd personally recommend using Laravel Passport. If you authenticate using Laravels standard auth procedure you can then add Laravel Passports
CreateFreshApiToken
middleware (docs here). This lets you consume your API locally without having to worry about tokens.It also has the added bonus of being able to take advantage of the power of oAuth with your API endpoints if you expand going forward.
I'm trying to build a hybrid Laravel Vue app and I'm really struggling with global variables, most specifically things like "does the entire application have inventory management turned on or not?". This is generally a read-only variable that should be available "everywhere". I normally put this in .env but I have a global true/false setting as well, inventory_enabled.
I like the
windows.variable_name
idea, but where I get confused is:When to use Vue.prototype?
In your example, you mention "process.env.API_DOMAIN". Where does this extra variable process.env come from? Is this now window.process.env?
At what point do I invoke Vuex? My application heavily relies on Vuex but when refreshing the browser window refresh Vuex state also get trashed so now I'm moving to local storage...now do I also store my global setting in Vuex AND localstorage?
The reason why I'm building this hybrid application is I still want to use Blade and scaffolding and so on, and all the other goodies that come with Laravel, but there are large parts of my front-end that needs Vue's reactivity to make the pages more responsive and interactive..
The global variables (.env style) are really getting me down. I just want one simple way.. :-)
Rather than echoing manually you can also let this package do it for you: github.com/laracasts/PHP-Vars-To-J...
Any worse suggestions? :D
I honestly believe that the best answer is 'using a rest API'. Mix a single page framework with php can create a huge mess.
Edit: Lumen and Vue/Angular it's a great combination
Have you tried inertia yet github.com/inertiajs/inertia-larav...
great post. really learnt something new
You can do all this in the View::composer. You can even access the store and add variables to it then export with
View::share('store', json_encode($store));
Good overview. I actually worked at a company that stored custom JS components on the window. It worked and for the small number of components that we had, organization never became an issue.