DEV Community

Cover image for Using React.JS as a Micro Frontend in Blazor WASM
Alexander Selorm Kubi
Alexander Selorm Kubi

Posted on

Using React.JS as a Micro Frontend in Blazor WASM

Table Of Contents

TL;DR

Here is a link to the github repository. Feel free to clone, download or fork and make PRs.
https://github.com/XanderSelorm/MicroFrontendsExample

Disclaimer

Kindly note that this tutorial is for educational purposes only and that this set up or architecture has not been tested in a production environment yet.

In our previous part of this series, we looked setting up the environment and folder structure for the Micro Frontends.

Configuring the Projects

ReactMicroFrontend Project

Since the ReactMicroFrontend is basically a JavaScript project, NPM will obviously be used as the default package manager.

To initialize NPM in the ReactMicroFrontend, using the terminal, ensure that you are in the root directory and you have Node.js and NPM installed globally on your computer. If not, download it from here. Then continue by running the following command in the root directory of the project:

npm init
Enter fullscreen mode Exit fullscreen mode

Since this project is for tutorials purposes only, we'll keep the default values when initializing NPM here.

With that done, let's look at how to bundle out JavaScript codes.
Since we're setting up the React Library manually, let's decide on what our bundler will be. For the sake of this tutorial, ‘Parcel’ will be used instead of usual webpack for the bundling of the React application.

Now that we have npm installed and initialized in our project, let's use it to install Parcel. If you want to know more about Parcel, check it out.

Run the following command in the root directory of the MicroFrontend (React) project in question:

npm install parcel --save-dev
Enter fullscreen mode Exit fullscreen mode

Now that this is done, let's determine where our React code will be bundled to upon build.

  • Open the package.json file in the ReactMicroFrontend project and modify the following lines:
{
  //destination path
  "main": "wwwroot/dist/app.js",

  //origin path
  "source": [
    "src/index.jsx"
  ],

  //scripts
  "scripts": {
    "build": "parcel build src/index.js",
    "clean": "del-cli wwwroot/dist/* node_modules",
  },
}
Enter fullscreen mode Exit fullscreen mode

When you take a critical look at our clean script, you'd realize the use of a package called del-cli. This package is used for permanently deleting files and directories. This packages needs to be installed globally before it can be used.
Run the following command in your terminal to install it:

npm install --global del-cli
Enter fullscreen mode Exit fullscreen mode

MicroFrontendExample.Shell Project

Awesome! With that done, save the file and let's look at how to make sure our JavaScript code from our MicroFrontend is also bundled into the App Shell/Container App.
To do this, we'll have to go back into the directory of our App Shell/Container App and then run a few commands.

In the startup application, ‘Webpack’ will be used to bundle all the JavaScript frameworks together into the main application/App Shell. And since we'll be using NPM here too, we'll initialize NPM in this directory too and then install the Webpack. Use the following commands by running them in the root directory of the startup project/App Shell:

Don't forget to keep the default values for NPM. (Well, you can still go ahead and customize it if you wish)

npm init && npm install webpack --save-dev && npm i -D source-map-loader && npm install --save-dev webpack-cli
Enter fullscreen mode Exit fullscreen mode

If the above commands fail, run them one after the other, like so:

npm init
Enter fullscreen mode Exit fullscreen mode
npm install webpack --save-dev
Enter fullscreen mode Exit fullscreen mode
npm install --save-dev webpack-cli
Enter fullscreen mode Exit fullscreen mode

...and then

npm i -D source-map-loader
Enter fullscreen mode Exit fullscreen mode

Integrating the Micro Frontends into the App Shell/Startup Application

  • In the Startup Project’s ‘App.razor’ file, we'll load the entry-files of the class libraries (micro frontends) as assemblies.

Do this by adding the following lines of code to the App.razor file:

@using System.Reflection

<!-- Default File Content -->

@code {
    private List<Assembly> LoadedAssemblies = new List<Assembly>()
    {
        typeof(ReactMicroFrontend.App).Assembly
    };
}
Enter fullscreen mode Exit fullscreen mode
  • In the same file, on the <Router> tag, add the AdditionalAssemblies attribute and assign the LoadedAssemblies value to it.
<!-- AdditionalAssemblies="@LoadedAssemblies" -->
<Router AppAssembly="@typeof(Program).Assembly" AdditionalAssemblies="@LoadedAssemblies" PreferExactMatches="@true">
Enter fullscreen mode Exit fullscreen mode
  • In the Startup Project’s _Import.razor file, add the namespaces of the various micro frontend applications in order to make them available throughout the startup project:
@using ReactMicroFrontend
Enter fullscreen mode Exit fullscreen mode

Awesome! A couple of things more to do...

  • Let's begin by modifying the package.json file over here too. we'll add the build and clean scripts to the scripts object.
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "clean": "del-cli wwwroot/dist/* node_modules"
  },
Enter fullscreen mode Exit fullscreen mode

Now, let's add the configurations for webpack. We'll do this by adding a new file and name it as webpack.config.js.

  • Right click on the project > Add > New item > Javascript File.

  • Change the name to webpack.config.js, and click Add.

Adding JS File

In the webpack.config.js file, add the following block of code, customize it if the need be, and save it.

const path = require('path');
const fs = require("fs");

module.exports = [
  {
    name: "get-react",
    entry: () => fs.readdirSync("../ReactMicroFrontend/wwwroot/dist/").filter(f => f.endsWith(".js")).map(f => `../ReactMicroFrontend/wwwroot/dist/${f}`),
    devtool: "source-map",
    mode: "development",
    output: {
      filename: "app.js",
      path: path.resolve(__dirname, "./wwwroot/dist/react/")
    },
    module: {
      rules: [
        {
          test: /\.js$/,
          enforce: "pre",
          use: ["source-map-loader"]
        }
      ]
    }
  }
]
Enter fullscreen mode Exit fullscreen mode
  • Finally, let's make sure that our React script is added to our index.html file. If not, before the closing body tag in the index.html file, add:
<script src="dist/react/app.js"></script>
Enter fullscreen mode Exit fullscreen mode

Automating the Build Scripts

If you've read up to this point, congratulations! This is the last step and then we'll take out app for a test ride 😀!

By now, I'm sure you are wondering whether we'll be calling the build scripts manually for each project? The answer? Hell no! 😀 We'll automate that too. So that when the build command is called for the dotnet projects, that of our JavaScript microfrontends are called too.

Let's look at how to implement that:

  • We'll edit the project files of both the MicroFrontendExample.Shell and any of our microfrontend which uses JavaScript code; this includes out ReactMicroFrontend.

If you're using VS Code, it's easy to locate the project files.

But when you're using Visual Studio, right click on the project > Edit Project File.

  • Before the </Project> closing tag, add the following block of code:
<Target Name="npm restore" BeforeTargets="BeforeBuild">
        <Exec Command="npm install" />
</Target>

<Target Name="webpack" AfterTargets="Build">
    <Exec Command="npm run build" />
</Target>

<Target Name="webpack clean" AfterTargets="Clean" Condition="Exists('node_modules')">
    <Exec Command="npm run clean" />
</Target>
Enter fullscreen mode Exit fullscreen mode

Awesome! Congratulations for making it up to this point! Now we're free to build our application. :D

Ooopss!! There are Errors!?? Chill bro, 😀, this error was expected. 😊
This error occurred because we directed the Parcel bundler to an index.js file which doesn't exist. This is because we haven't installed and set up our React.JS yet.

This brings us to our next and final topic:

Installing and Setting Up React.JS

This final step should be fairly easy to do. We'll run a couple of commands, run a few lines of code and then we call it one hell of a guide! 😀

  • To begin, let's install react and react-dom. Run the following command in your terminal:
npm install --save react react-dom
Enter fullscreen mode Exit fullscreen mode
  • Secondly, let's create a new file, name it index.js in the src folder.

  • Add the following code block to the new file you created:

import React from "react";
import ReactDOM from "react-dom";

window.renderApp= () => {
  const domElement =
    document.getElementById("react-app") ||
    document.querySelector("#react-app");

  if (domElement) {
    ReactDOM.render(<h1>Hello, React🌐!</h1>, domElement);
  }
};

Enter fullscreen mode Exit fullscreen mode
  • Finally, feel free to run the application, navigate to "/ReactMicroFrontend", and experience the power of Blazor!

Your final app should look like this:

Final Cut

Here is a link to the github repository. Feel free to clone, download or fork and make PRs.
https://github.com/XanderSelorm/MicroFrontendsExample

Thank you very much for reading. Follow me for more interesting guides and content. And oh, don't forget to leave a reaction 😉. I'll be grateful 😊

See you later, cheers!

Top comments (8)

Collapse
 
estrelajoao profile image
EstrelaJoao

Hey!
Currently I'm collecting some ideas and experiments for an architecture that I'm defining for a project in my company and I found this article really interesting but I have one big doubt.

Is there any way to do this with different solutions?

For example:

Having an app shell that will call 3/4 microservices that already have their frontend in Blazor? Is this a viable way to do it?

Collapse
 
xanderselorm profile image
Alexander Selorm Kubi

Hi!
I hope my reply is still useful. Haha.

Your idea is interesting, unfortunately, I haven't experimented that angle yet.

Have you been able to find a solution?

Collapse
 
booster2ooo profile image
Booster2ooo

Nice article but, and correct me if I'm wrong or missed a point, one of the key concept of micro front-ends is the ability to build each µFront-end independently from another, and, especially, from the shell/container app. Otherwise, it's not really a µFrontend but rather a "modular" app.

Collapse
 
xanderselorm profile image
Alexander Selorm Kubi • Edited

I'm sorry for the late reply :).

Well, I wouldn't say you're wrong per your assessment. Personally, I agree with the notion that when a "modular" app has its frontend modules built with different technologies and maintained by different teams, such frontend modules may also be called as Micro-Frontends.
Have a read from the originators of the concept here: thoughtworks.com/radar/techniques/...

Collapse
 
artydev profile image
artydev

Great thank you

Collapse
 
mohammad72021 profile image
Mohammad72021

Hi. Can you Describe how handle state management in this type projects .

Collapse
 
xanderselorm profile image
Alexander Selorm Kubi

You can take a look at Fluxor. And you'll also need JS InterOp

Collapse
 
kayomez profile image
Kayomez

Is there any way to add js packages to this? Tried giving it a go but it doesn't seem to like them.