A user requests a page on the Ruby on Rails server.

The server gathers the necessary data to render the page.

The ERB template uses a custom renderer to request components to a Hypernova server.

Hypernova server renders all the requested components using React and sends them back to the Ruby on Rails server.

The components are injected in the generated page by ERB.

The Ruby on Rails sends back the HTML markup plus the javascript files to the browser.

On the browser, JavaScript is used to progressively enhance the application and make it dynamic.

Using this architecture Airbnb can reuse their React components for server-side and client-side rendering and decoupling the presentation of their Monolith built ontop Ruby on Rails.

Here a detailed article wrote by the Airbnb Engineering team.

Using Hypernova on Laravel

Laravel is a PHP web framework to build modern web applications similar to other frameworks like ASP.net MVC, Ruby on Rails and AdonisJS.

Laravel Application Diagram

Laravel uses Blade as the template engine for server-side rendering, and Laravel Mix to compile assets like Javascript, CSS, and Vue.js components for client-side rendering.

Supporting Vue.js on Hypernova

Airbnb Hypernova doesn’t support Vue.js out of the box but it enables us to make it developing our own Hypernova bindings, so I created hypernova-vue.

I wrote this article about how to use Vue.js with Hypernova, also you can use this generator.

1st Approach — Hypernova Client

Once the Hypernova server was configured to use Vue.js I created a custom directive in Blade in order to place hypernova components inside the Blade views.

Hypernova Blade Directive in AppServiceProvider.php

The Hypernova directive uses a facade which pushes the requested component into the hypernova-php client and adds a placeholder in the template view necessary to place the rendered component later.

The hypernova client is a singleton so we can persist the requested components in order to get them from the hypernova server later.

Hypernova Class — pushJob

Finally, Blade renders the page based on the template view and a Laravel middleware use the Facade to modify the original response. The Facade behind of scenes uses the Hypernova client to request the components to Hypernova server and replaces the placeholders with the rendered components on only one step.

Hypernova Middleware

I took some ideas of laravel-hypernova package but I didn’ use it because the library is not compatible with Laravel 5.8 yet and I had issues handling incoming errors from hypernova server.

Using the Hypernova directive

Laravel controller only needs to pass the view name and the data to Blade using the view function.

Returning a view inside the route handler

The default layout contains the HTML document and defines a NavBar component using the hypernova directive.

Default Layout using Blade

The welcome view uses the default layout and defines a Home component using the hypernova directive as well.

Welcome view

Once the HTML is rendered this is the result:

The page is server-side rendered and client-side dynamic using the same Vue.js components, which is pretty cool for SEO.

I enabled Laravel to universal renders Vue.js components using Hypernova server but it’s still coupled to some implementation details. Laravel needs to interact with the Hypernova server directly using the Hypernova client, so the architecture requires to develop a Hypernova client for each language or web framework.

Hypernova proxy approach

After analyzing deeply the architecture I found a common communication interface closely to the micro-frontends principles.

The HTML generated by Blade contains the placeholders with all the information necessary to generate a batch request to Hypernova server, even if the hypernova server fails to render the view, the client-side scripts will render the component on the browser making the Frontend resilient.

Based on the Laravel middleware approach I decided to put a Reverse Proxy between the client and the Laravel application in order to server-side include (SSI) the views coming from Hypernova server.

I gave a try to Nginx extending it using OpenResty but I found some implementation constraints using the HTML parser and HTTP Client for Lua.

Finally, after researching a lot I decided pick Go to develop it. Go has an HTTP Client and Reverse Proxy Server module out of the box and a pretty cool library to parse and mutate the DOM using query selectors.

How Hypernova proxy works

Using Hypernova proxy Laravel only needs to use the Hypernova directive in order to render the placeholders that Hypernova proxy uses to server-side include the Hypernova views in the page as we were doing before with the Laravel middleware, but now we can reuse Hypernova proxy in order to universal render views using others web frameworks.