Universal Rendering in Laravel using Vue.js and Ara Framework
Universal Rendering consists in rendering pages on the server and making them interactive on the browser using the same view components built with a library such as React, Vue.js, Angular, etc.
Nowadays, JavaScript frameworks such as Next.js, Nuxt.js, and NgUniversal make this duty easier. However, how can we achieve it on non-JavaScript frameworks like Laravel?
Setup Laravel
Download Laravel installer using Composer.
composer global require laravel/installer
Create a folder named ara-laravel
and run the following command inside the folder to create a Laravel project.
composer create-project --prefer-dist laravel/laravel laravel-site
Once the project is created run the Laravel application on http://localhost:8000/.
php artisan serve
Browser:
Set up the Nova service
We'll create a Nova service using Vue.js.
Install Ara CLI:
npm i -g ara-cli
Create the Nova service:
ara new:nova -t vue nova
Go to the Nova service folder:
cd nova
Run Nova service:
yarn dev
The Nova service runs on http://localhost:3000.
Test the Nova Service.
Once the Nova service is running you can make a POST
request to http://localhost:3000/batch using a payload like:
{
"uuid": {
"name": "Example",
"data": {
"title": "Ara Framework"
}
}
}
The results
property in the response contains the html
of the view rendered by the Nova service.
Example:
{
"success": true,
"error": null,
"results": {
"uuid": {
"name": "Example",
"html": "<div data-hypernova-key=\"Example\" data-hypernova-id=\"4d9e81bd-6413-4661-ab56-ed5bb4f59cae\"><h1 data-server-rendered=\"true\">Ara Framework</h1></div>\n<script type=\"application/json\" data-hypernova-key=\"Example\" data-hypernova-id=\"4d9e81bd-6413-4661-ab56-ed5bb4f59cae\"><!--{\"title\":\"Ara Framework\"}--></script>",
"meta": {},
"duration": 1.210146,
"statusCode": 200,
"success": true,
"error": null
}
}
}
Setup Nova Directive in Laravel Blade
Install Nova Directive for Laravel Blade using Composer inside the laravel-site
folder.
composer require marconi1992/hypernova-blade-directive
Add NovaServiceProvider
in application config config/app.php
return [
...
'providers': [
...
Illuminate\View\ViewServiceProvider::class,
/*
* Package Service Providers...
*/
Marconi\Nova\NovaServiceProvider::class,
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
...
]
...
]
Use Nova Directive in a Laravel view
Add the Example
view on the welcome page.
resources/views/welcome.blade.php
<html>
...
<body>
...
<div class="content">
<div class="title m-b-md">
Laravel
</div>
<!-- Nova Directive starts -->
@hypernova('Example', [ 'title' => 'Ara Framework'])
<!-- Nova Directive ends -->
<div class="links">
<a href="https://laravel.com/docs">Docs</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://blog.laravel.com">Blog</a>
<a href="https://nova.laravel.com">Nova</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
</div>
...
</body>
</html>
Server-side rendering
The Nova View is not rendered yet, we need to implement Nova Proxy in order to server-side render and include the Nova views.
The Nova Direvitve renders a placeholder that contains the necessary information to enable Nova Proxy to communicate with the Nova service and include the Nova view.
<div data-hypernova-key="Example" data-hypernova-id="d198fa6c-c9ec-11e9-a223-8c85903a4c93"></div>
<script type="application/json" data-hypernova-key="Example" data-hypernova-id="d198fa6c-c9ec-11e9-a223-8c85903a4c93"></script>
Nova Proxy
Nova proxy is a service to implement Universal Rendering with any view library (React, Vue.js, etc) on any web platform (Laravel, Flask, etc). For example, in this demo, we'll render a view using Vue.js into a web application built with Laravel.
How it works:
A user requests a page to the Nova Proxy.
The Nova Proxy passes the request to the website server.
The website uses a Nova Directive to render the placeholders where the Nova views should be included.
The website sends back the HTML generated to the Nova Proxy.
The Nova Proxy includes the Nova views on the placeholders and sends back the HTML to the browser.
Finally, on the browser, JavaScript is used to progressively enhance the application and make it interactive. Read more here about the Nova Architecture.
Setup Nova Proxy
Create a configuration file for Nova Proxy in the root folder:
touch nova-proxy.json
Add the following configuration in nova-proxy.json
file to proxy the incoming requests to the Laravel web server.
{
"locations": [
{
"path": "/",
"host": "http://localhost:8000",
"modifyResponse": true
}
]
}
Run Nova Proxy
Before running the command we need to set the HYPERNOVA_BATCH
variable using the Nova service endpoint.
export HYPERNOVA_BATCH=http://localhost:3000/batch
You need to run the following command where the noxa-proxy.json
file was created or pass the --config
parameter with the configuration file path.
ara run:proxy --config ./nova-proxy.json
The command runs Nova Proxy on http://localhost:8080.
Now, see how the Nova view is displayed, it's because Nova Proxy includes the Nova view in the page coming from the Laravel application.
Browser:
Client-side rendering
The Example
view is rendering only a simple heading. We can make it interactive adding an input element that changes the heading text.
Replace the nova/src/components/Example.vue
with the following code:
<template>
<div>
<h2>{{title}}</h2>
<div>
<input type="text" v-model="title">
</div>
<br/>
</div>
</template>
<script>
export default {
props: ['title']
}
</script>
Now, the Nova view displays an input element but the heading text doesn't change when we type something. It's because we need to add the client-side script.
Hydrate Nova views on the browser
Hydration is the process of mounting a view component on the browser using the state used when it was rendered on the server.
In order to hydrate the views we need to load the client.js
script on the browser.
Update the welcome.blade.php
file in the Laravel application:
<!DOCTYPE html>
<html lang="en">
<head>
....
</head>
<body>
....
<script src="http://localhost:3000/public/client.js"></script>
</body>
</html>
Conclusion
Nova Proxy enables us to use modern view libraries on any web framework. So if you previously developed a web application using non-Javascript frameworks (Laravel, Flask, Ruby on Rails, etc) then Nova Proxy can help you to gradually migrate its views to a JavaScript view library (React, Vue.js) in a short period of time.