<

Micro Frontends with SSR in Ara-Framework

Hello everyone, my name is silverbirder. My latest interest is Micro Frontends.

https://silverbirder.github.io/blog/contents/microfrontends

I'm currently learning how to approach Micro Frontends using a framework called Ara-Framework.

What is Ara-Framework?

Build Micro-frontends easily using Airbnb Hypernova

Ara-Framework uses the Hypernova framework developed by Airbnb to build Micro Frontends.

What is Airbnb Hypernova?

A service for server-side rendering your JavaScript views

Briefly, Hypernova is a library that returns rendered results (HTML) when you pass it data. This has the advantage that data construction and rendering can be clearly separated.

Ara-Framework architecture

The architecture diagram of Ara-Framework looks like this

ara framework overview
ara framework overview

The components are as follows. (Also explained on the official page at ↑)

  • Nova Proxy.
    • Proxies browser access to Layout.
    • Parses the HTML returned from Layout and queries the Nova Cluster for Hypernova placeholders, if any.
    • Embeds the HTML returned from Nova Cluster into Hypernova placeholders and returns the HTML to the browser.
  • Nova Directive (Layout)
    • Constructs the overall HTML, embedding Hypernova placeholders.
    • Node.js, Laravel and Jinja2 are supported.
  • Nova Cluster.
    • A cluster that manages Nova Binding.
    • Located between Nova Proxy and Nova Bindings.
  • Nova Bindings (Hypernova)
    • It is passed data and returns the result of rendering HTML. (Hypernova is used here).
    • React, Vue.js, Angular, Svelte and Preact are supported.

By clearly separating Layout and Rendering (Nova Bindings) in this way, we feel that independence and scalability are good. A cache layer between each layer is also expected to improve performance.

For more information, see the official page.

Ara-Framework sample code

We have actually used Ara-Framework. The sample code is given below. https://github.com/silverbirder/micro-frontends-sample-code-2

The package.json looks like this.

package.json

  "scripts": {
    "cluster": "cd cluster && PORT=5000 ara run:cluster --config . /views.json",
    "layout": "cd layout && PORT=8080 node . /bin/www",
    "proxy": "cd proxy && HYPERNOVA_BATCH=http://localhost:5000/batch PORT=8000 ara run:proxy --config . /nova-proxy.json",
    "search:dev": "cd search && PORT=3000 . /node_modules/webpack/bin/webpack.js --watch --mode development",
    "product:dev": "cd product && PORT=3001 . /node_modules/webpack/bin/webpack.js --watch --mode development", "product:dev"
    "dev": "concurrently -n cluster,layout,proxy,search,product \"npm run cluster\"\"npm run layout\"\"npm run proxy\"\"npm run search:dev\"\"npm run product:dev\"",
  }

The steps to create the product are as follows. 1.

Create a Nova Proxy 1. Create a Nova Directive (Layout) 1. Create Nova Cluster

  1. create Nova Bindings (Hypernova)

To use the Ara-Framework, the following preparations must be made.

$ npm i -g ara-cli

Nova Proxy

Nova Proxy will proxy to Nova Directive, so write its host.

nova-proxy.json

{
  "locations": [
    {
      "path": "/",.
      "host": "http://localhost:8080",.
      "modifyResponse": true
    }
  ]
}

Nova Proxy also needs to specify a URL in the variable HYPERNOVA_BATCH in order to query the Nova Cluster. To run Nova Proxy, execute the following command.

$ HYPERNOVA_BATCH=http://localhost:5000/batch PORT=8000 ara run:proxy --config . /nova-proxy.json

Nova Directive (Layout)

Nova Directvie uses hypernova-handlebars-directive. This can be used with the Node.js handlebars template engine (hbs).

It generates Express templates.

$ npx express-generator -v hbs layout

Without going into too much detail, create the following HTML file (hbs): $ npx express-generator -v hbs layout

layout/index.hbs

<h1>{{title}}</h1>
<p>Welcome to {{title}}</p>

{{>nova name="Search" data-title=title }}

<script src="http://localhost:3000/public/client.js"></script>
<script src="http://localhost:3001/public/client.js"></script>

{{>nova}} is the Hypernova placeholder hypernova-handlebars-directive. name is the name of the Nova Bindings (explained later) and data-* is the data to be passed to the Nova Bindings. The reason client.js is loaded in the script is to realise the CSR.

The move is the same as when running Express, and is as follows.

$ PORT=8080 node . /bin/www.

Nova Cluster

Nova Cluster manages Nova Bindings.

views.json

{
  "Search": {
    "server": "http://localhost:3000/batch"
  },
  "Product": {
    "server": "http://localhost:3001/batch"
  }
}

Search and Product are the names of the Nova Bindings you will create later; server is the URL where Nova Bindings is running.

To run Nova Cluster, execute the following command.

$ PORT=5000 ara run:cluster --config . /views.json

Nova Bindings

To create Nova Bindings, run the following command.

$ ara new:nova search -t react
$ ara new:nova product -t vue

From there, here is a slightly modified version from the auto-generated directory

search/Search.jsx.

import React, { Component } from 'react'
import { Nova } from 'nova-react-bridge'

class Search extends Component {
  render() {
      <div>
        <div>Search Components!</div>
        <table>
          <tr>
            {['🐙', '🐳', '🐊', '🐍', '🐷', '🐶', '🐯'].map((emoji, key) => {
              return <td key={key}>
                <Nova
                  name="Product"
                  data={{title: emoji}}/>
              </td>
            })}
          </tr>
        </table>
      </div>
  }
}

Not described so far, but we use nova-react-bridge, which is Nova Bridge. It is similar to Nova Directive, but the available files are compatible with JS frameworks such as React and Vue.js. This means that it can also be used for Nuxt.js, Next.js and Gatsby.js.

This sample Nova Bridge works with CSRs; to work with SSRs, you will (probably) need to insert a Nova Proxy.

product/Product.vue

<template>
  <div>{{title}}</div>
</template>

<script>
export default {
  props: ['title']
}
</script>

To get these working in Nova Bindings, run the following command.

# search.
$ PORT=3000 . /node_modules/webpack/bin/webpack.js --watch --mode development
# product
$ PORT=3001 . /node_modules/webpack/bin/webpack.js --watch --mode development

Checking that it works

We need to run everything we have introduced so far concurrently. So use concurrently.

$ concurrently -n cluster,layout,proxy,search,product "npm run cluster" "npm run layout" "npm run proxy" "npm run search:dev" "npm run product:dev"

As an action, the image will look like this

nova results
nova results

Finally.

Again, the Ara-Framework allows a clear separation between data construction (Nova Directive) and rendering (Nova Bindings). Also, the rendering parts can be independent of each other. For the parts of the API not introduced here, you need to think about who will manage them and how.

However, the CSR javascript used in Nova Bindings contains duplicate code, which increases browser load times. This is where the Federation feature, available since webpack 5, comes in as a solution.

This was an introduction to the Ara-Framework!

If it was helpful, support me with a ☕!

Share

Related tags