DEV Community

Felipe Guizar Diaz
Felipe Guizar Diaz

Posted on

Implementing Microfrontends in Nuxt.js using Svelte and Ara Framework

Nuxt + Svelte

Demo code here

This article was originally written in Ara blog.

Nuxt.js is the most popular framework to easily develop Universal Applications using Vue.js. It also supports static websites, single-page, mobile, and desktop applications.

What is a universal application?

vue ssr diagram

The main characteristic of a universal application is it uses the same JavaScript code on the server and browser. Therefore we can use the same Vue.js components to server-side and client-side rendering and get the benefits of both worlds.

This course video explains more about Universal Applications with Nuxt.js.

What do Microfrontends role play here?

We know the Frontend technologies evolve pretty fast. Nowadays, Svelte has become very popular, and more developers have started using it.

Sapper is one alternative to develop universal applications using Svelte. However, Sapper is not too much mature like Nuxt.js or Next.js. What if we could use Svelte in Nuxt.js?.

This is a perfect scenario where we can take advantage of the Tech Agnostic principle of Microfrontends. So, Why we need to wait until Sapper become to mature like other frameworks? We shouldn't. We can re-use what already exists.

Setup Nuxt project

Create a folder named ara-nuxt and run the nuxt app generator create-nuxt-app inside the folder:

npx create-nuxt-app nuxt-site

The command asks for some configurations, choose the default options.

Finally, run the Nuxt application inside the nuxt-site folder:

PORT=8000 yarn dev

The Nuxt application runs on http://localhost:8000.

Browser:

Nuxt default page

Setup Nova Service

Create a Nova service that use Svelte to render the Nova views.

Install Ara CLI:

npm i -g ara-cli

Create the Nova service:

ara new:nova -t svelte nova

Go to the Nova service folder:

cd nova

Run Nova service:

npm run 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=\"4c08ba37-4b1a-4387-a883-99726e6b4617\"><h1>Hello Ara Framework</h1></div>\n<script type=\"application/json\" data-hypernova-key=\"Example\" data-hypernova-id=\"4c08ba37-4b1a-4387-a883-99726e6b4617\"><!--{\"title\":\"Ara Framework\"}--></script>",
      "meta": {},
      "duration": 1.210146,
      "statusCode": 200,
      "success": true,
      "error": null
    }
  }
}

Setup Nova Bridge in Nuxt.js

The Nova Bridge enables us to use Nova Views on any view library such as React, Vue.js, and others. Read more about Nova Bridge here.

Go to nuxt-site folder and install nova-vue-bridge in Nuxt.js:

yarn add nova-vue-bridge

Add @babel/plugin-transform-modules-commonjs plugin for babel in nuxt.config.js file.

nuxt.config.js

{
  ...    
  build: {
    /*
    ** You can extend webpack config here
    */
    babel: {
      plugins: [
        '@babel/plugin-transform-modules-commonjs'
      ],
    },
    ...
  }
}

Implement Nova view (Svelte) in Nuxt.js

Use the Nova component into a Nuxt page pages/index.vue.

Import Nova component:

<script>
import Nova from 'nova-vue-bridge'
import Logo from '~/components/Logo.vue'

export default {
  components: {
    Logo,
    Nova
  }
}
</script>

Use Nova component in page:

<template>
  <div class="container">
    <div>
      <logo />
      <!-- Nova component starts -->
      <nova name="Example" :data="{ title: 'Ara Framework' }" /> 
      <!-- Nova component ends -->
      <h1 class="title">
        nuxt-site
      </h1>
      ...
    </div>
  </div>
</template>

Client-side rendering

Update the client-side entry point in order to render and mount the view on placeholder rendered by Nova Bridge.

nova/src/client.js

import { renderInPlaceholder } from 'hypernova-svelte'

import Example from './components/Example.svelte'

const { document } = global

document.addEventListener('NovaMount', (event) => {
  const { detail: { name, id } } = event
  if (name === 'Example') {
    return renderInPlaceholder(name, Example, id)
  }
})

Add client-side script on page:

pages/index.vue

export default {
  components: {
    Logo,
    Nova
  },
  head: {
    script: [
      { src: 'http://localhost:3000/public/client.js' }
    ]
  }
}

Run the Nuxt application again:

PORT=8000 yarn dev

Finally, the Nova view is rendered and mounted correctly displaying a heading text saying "Hello Ara Framework"

Browser:

Nova vue csr rendered

Server-side rendering

The Nova View is not server-side render yet, so if we disable the client-side script nothing is displayed. We need to implement Nova Proxy in order to server-side render and include the Nova views. Read more about the Nova Architecture here.

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 Nuxt application.

{
  "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

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 even if the client-side script is disabled, it's because the page coming from the webserver contains the rendered HTML for the Nova view.

Update the Example View

The Example view is just displaying a heading. We can update it adding an input that changes the heading text.

nova/src/components/Example.svelte

<script>
  export let title;
</script>

<div>
  <h1>Hello {title}</h1>
  <input type="text" bind:value={title}>
</div>

Browser:

Example view updated

Conclusion

Micro-frontends enable us to integrate different frameworks into the same page, but it doesn’t mean that we should mix frameworks arbitrarily. We should define standard frameworks and libraries across the company.

However, this level of isolation gives us the flexibility to evolve our web application along with the web technologies.

Top comments (0)