Retailgear whitelabel retail software logo

How to create your own microfrontends

You can develop your own microfrontend by using:

Angular


Follow these steps to set up your workspace and create a new angular project: Angular - Setting up the local environment and workspace.


Be sure to use the same version of the main app.


After setting up your environment, creating the project and installing all the node dependencies, create your own component by using the following command:


  

ng generate module [module_name] --route [module_name] --module app.module 



You can add your own styling, and if you are going to use Bootstrap check the version used on the retailgear-app-main-v1 and use the same for your component, otherwise it will give you some dependency issues and some classes will not work properly. Create your components, style them and install all the dependencies that you need.




How to integrate your microfrontends in the retailgear-app-main-v1.


To use your microfrontends, you need to use the Module Federatio, integrated in Webpack, it provides an official solution for the implementation of microfrontends. For more information about the Module Federation, check the following link: The Microfrontend Revolution: Module Federation in Webpack 5 - ANGULARarchitects.


To add and use the Module Federation in your angular project, read the following article, besides the steps, it will provide you more information on how it works: The Microfrontend Revolution: Module Federation with Angular - ANGULARarchitects.


In our case, the host will be the main application (retailgear-app-main-v1) and your microfrontend project will be the remote. We use “mfe1” as an example of a microfrontend project, as in the guide linked above.



  

ng g @angular-architects/module-federation:init --project mfe1 --port 4201 --type remote



By executing the above command, it will generate a webpack.config.js within your microfrontend project folder. In the generated webpack.config.js file, you will have to expose your module. For example:



FILE: webpack.config.js (REMOTE)

  

new ModuleFederationPlugin({  

      // For remotes (please adjust)

      name: “mfe1”,

      filename: “mfe1.js”,

      exposes: {

          './Module': './projects/mfe1/src/app/flights/flights.module.ts'',

      },

      shared: share(sharedLibrary)

})



In the “exposes” property, you will have to define which module you want to expose, by writing the absolute path of the module and giving it a unique name, with this name the host can identify your module. Webpack will lazy load your exposed module in the JS file, defined in the “filename” property.


The shared property defines the packages to be shared between the host and the remotes. Within the sharedLibrary variable you can define the packages that you want to be shared, like so:



FILE: webpack.config.js (REMOTE)

  

const sharedLibrary = {

  "@angular/core": { singleton: true, requiredVersion: 'auto' },

  "@angular/common": { singleton: true, requiredVersion: 'auto' },

  …

};



Of course you will need to integrate your microfrontends in the host, to do that you will need to open the webpack.config.js file of the host, and include your microfrontends in the “remotes” section, like the example below:



FILE: webpack.config.js (HOST)

  

plugins: [

    new ModuleFederationPlugin({

     remotes: {

        ...

        "mfe1": "http://localhost:4201/mfe1.js",

        ...

     }...

]


The remote section maps the “mfe1” path to the separately compiled microfrontend.


That is how you can integrate your microfrontends in the retailgear-app-main-v1. For more details read the article below: The Microfrontend Revolution: Module Federation with Angular - ANGULARarchitects




How to use your microfrontends.


There are two ways to use your microfrontends, we explain them below:



ROUTING

You can invoke your microfrontends, from the URL, by going to the routing file of the retail gear-app-main-v1, where you want to lazy load it, and define the path for your microfrontends. For example you can define your path like this, replace name and path according to your needs:



  

…{

    path:'flights',loadChildren:() => 

        import(`mfe1/Module`).then(module => module.[FlightsModule]),       

        data: {title: '[title]'}, //you can pass some data here, e.g. title.

        canActivate: [AuthGuard] //you can activate route guards too.

}…


FILE: Some routing file (HOST)


If by importing the module, you get an error from typescript, just create a dummy declaration typescript file, name it “decl.d.ts” within the same directory and declare the module in the file, like so:



  

declare module 'mfe1/Module';

COMPONENT

In a single page, you can also integrate multiple microfrontends from different parts. In this case, you will not be able to use the ROUTING method, you will have to use the component routing module. This means that whenever you want to use another microfrontends within a page, from another module, you will have to put a “placeholder”, in the HTML file of that page, and give it an ID:


  

<ng-template [element_id]></ng-template>


After setting up the HTML file, you will need to set up its component.ts file. First you will need to declare all the variable that you need and the “placeholder” element, that you defined in the HTML file, also you have to import and initialize some classes, as follows:



FILE: ...component.ts file of the module where you want to place the external component.

  

import {Compiler, Component, Injector, NgModuleRef, OnInit } from '@angular/core';


export class ExampleComponent implements OnInit, AfterViewInit {

 componentRef: any;

 @ViewChild('[element_id]',{read:ViewContainerRef})[element_name]!: ViewContainerRef;

 constructor( 

        private compiler: Compiler, 

        private injector: Injector

 ){...}

...

}


Make sure to import your module, then you will have to define the “loadDynamicComponent” function,or  you can call it whatever you want:



FILE: ...component.ts file of the module where you want to place the external component.

  

...

loadDynamicComponent() {

    try {

      import('[module_path]').then(({ [module_name] }) => {

        this.compiler?.compileModuleAsync([module_name]).then(moduleFactory => {

          const moduleRef: NgModuleRef<typeof [module_name]> = moduleFactory.create(this.injector);

          const componentFactory = moduleRef.instance.resolveComponent();

          this.componentRef = this.container.createComponent(componentFactory, undefined, moduleRef.injector);


          //You can add other lines here if needed.

        

        });

      });

}


This function will extract the component file from the module, and inject it in the placeholder defined in the HTML file. It uses compileModuleAsync method to compile the given module, this method belongs to “Compiler”, a Class provided by angular (Angular - Compiler).


Inside moduleFactory there will be all the core of the given module extracted with the NgModuleRef.


The resolveComponent method will return one particular component of the given module, and it will place the result inside the variable componentFactory, after this line of code, the function will create an object for that particular component and assign it to the “placeholder” element created in the HTML file.


Note that if somehow you get an error from the resolveComponent, you will need to define that method in the module file of where you want to use it.


Last thing to do is to call the method wherever you want, in our case we are going to call it in ngOnInit():



FILE: ...component.ts file of the module where you want to place the external component.

  

ngOnInit(): void {

   this.loadDynamicComponent(); // Load dynamic component

}


By following one of these ways, you will be able to use your microfrontend on your main application! 🥳

We have also have a project example on how to create and use a custom microfrontend: Microfrontend project example: Jewels and watches (angular).



Share by: