Simplified Micro-Frontends in Vue

jherr

Jack Herrington

Posted on January 20, 2021

Simplified Micro-Frontends in Vue

Vue 3 is a fantastic platform for creating Micro-Frontend components. And there are great frameworks out there to help with that, such as SingleSPA and OpenComponents.

Unless you plan on integrating your Vue components into applications that use a different framework you simplify your architecture dramatically by Webpack 5’s Module Federation to share and consume Micro-FE components.

Scenario

Let’s say that you and I work for a tap list service. That’s a service that bars and restaurants use to list their available beverages online. The bars enter the data into our service, and then use an iframe embedded on their site to show customers what’s on tap today. This is a real service by the way, with multiple vendors. Here is the tap list for my local Happy Valley Growlers.

An iframe, while easy to implement, doesn’t integrate well onto the page. We can do better using Micro-Frontends!

The Growlers App

Our starting repo has a single Vue 3 application (on Webpack 5 and using Typescript) called growlers. And when we start it up we see three Micro-FE components.

Growlers Micro-FE components

There are three Micro-Frontend components:

  • Search  — Has controls that allow the customer to refine the list of taps to their liking.
  • Taps  — Shows the current list of available beverages that match the Search filter.
  • Cart  — Shows a list of beverages the customer has added to their cart.

Each of these components is implement in its own .vue file. And they “talk” through a shared data store, implemented in store.ts, that uses the Vue 3 reactive feature to share data between the components. The advantage of this approach in a Micro-Frontend context is that the application that consumes these components do not need to implement the shared data store. You just drop the components on the page and they connect automatically through the store.

Turning these components into Micro-Frontend components is as easy as editing the ModuleFederationPlugin in the webpack.config.js. It starts off looking like this:



new ModuleFederationPlugin({
  name: "starter",
  filename: "remoteEntry.js",
  remotes: {},
  exposes: {},
  shared: require("./package.json").dependencies,
}),


Enter fullscreen mode Exit fullscreen mode

From there we can change the name from starter to growlers and then expose the components as well as the store:



new ModuleFederationPlugin({
  name: "growlers",
  filename: "remoteEntry.js",
  remotes: {},
  exposes: {
    "./store": "./src/store",
    "./Cart": "./src/components/Cart",
    "./Search": "./src/components/Search",
    "./Taps": "./src/components/Taps",
  },
  shared: require("./package.json").dependencies,
}),


Enter fullscreen mode Exit fullscreen mode

This is telling Webpack 5 to expose these files for external consumption by other applications. We are exposing the store because it is used to load the customer data. Even if we didn’t expose the store code it would still be packaged up with the components because Module Federation is smart enough to package up all the code required to run any exposed module.

Setting Up The Consumer Application

Our next step in trying this out is to create a new Vue 3 project to consume these components. The simplest way to do that is to use degit to clone the starter project:



npx degit https://github.com/jherr/wp5-starter-vue-3 hv-growlers


Enter fullscreen mode Exit fullscreen mode

This will create a directory called hv-growlers that has a Vue 3 application that uses Tailwind for CSS and supports Typescript.

The next thing to configure is the webpack.config.js file to change the port number to 8081 (so that it doesn’t conflict with the growlers application). Then changing the ModuleFederationPlugin configuration to:



new ModuleFederationPlugin({
  name: "hvGrowlers",
  filename: "remoteEntry.js",
  remotes: {
    growlers: "growlers@http://localhost:8080/remoteEntry.js",
  },
  exposes: {},
  shared: require("./package.json").dependencies,
}),


Enter fullscreen mode Exit fullscreen mode

This connects our new application with the growlers application and allows us to import the components using simple import statements in the code.

With this configured we can add this code to bootloader.ts:



import { load } from "growlers/store";

load("hv-taplist");


Enter fullscreen mode Exit fullscreen mode

This will load the tap list for the client into the store.

Adding Micro-Frontends To The Page

Our next step is to change App.vue to have a template for the new page with spots in it to host the Micro-Frontend components. There is a template in a gist associated with this demo. When we replace the template in App.vue with this HTML we see this layout:

Consumer application template with callouts for Micro-FEs

We can then replace the App.vue code with this code:



import { Component } from "Vue";
import Taps from 'growlers/Taps';
import Search from 'growlers/Search';
import Cart from 'growlers/Cart';

export default {
  components: {
    Search,
    Taps,
    Cart,
  },
}


Enter fullscreen mode Exit fullscreen mode

Now the Micro-FE components from growlers are available to the template and we can replace the search, taps, and cart divs with <Search />, <Taps />, and <Cart /> tags. The result looks like this:

Micro-Frontend components integrated seamlessly into the other application

How easy is that? And this is a live runtime connection. The moment that a new version of growlers is pushed with a new implementation the consuming applications will update immediately.

Where To Go From Here

In the complete version of this example, which is shown in the YouTube video connected below, we continue on to:

  • Show the Vue consumer application integrating with the store to show an additional level of integration.
  • The growlers application upgraded to expose Vanilla Javascript wrappers around the Micro-Frontend components.
  • Another consumer application, this time using Vanilla Javascript and consuming the components using the Vanilla Javascript wrappers

There is a YouTube version of this article if you want a video walkthrough of the process:

Conclusions

Vue is a great way to make reusable components. When you combine that that Module Federation you now have reusable components you can easily runtime share between applications Micro-Frontend style. Even better, because you have access to them as full fledged Vue components you have a much deeper level of integration that we’ve seen in other Micro-Frontend frameworks.


💖 💪 🙅 🚩
jherr
Jack Herrington

Posted on January 20, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Simplified Micro-Frontends in Vue
modulefederation Simplified Micro-Frontends in Vue

January 20, 2021