Angular 8 — Mono-repositories & Micro-apps Architecture

Zaheer uddin Babar
Nov 3 · 8 min read

We have been developing SPA’s in angular for a while now. Angular has been our top priority for creating enterprise level application. Because it offers scale-ability, best practices, standards, features and stability going forward.

PROBLEM STATEMENT

Over the passage of time, our web apps have grown big and we have been into the situations, where we have to reuse a feature-a, which was created for application x but that particular feature is later on required in the application y as well.

Secondly, what if you have a huge product. You give your potential customer a demo and he feels that its a lot costly to have him buy the whole suite. So he prefers to have only one or a limited set of features in your product. How would you be extracting that mini application/s out of the huge code base.

Well — that would require some effort. In a typical angular architecture, we would be doing it the lazy-loading module way. Although lazy loading, decouple modules in a particular way but re-using that module in another app will still require some rework.

ISSUES

If you are doing it in traditional way, then there would be lots of copy pasting required(which also depends on any private npm repository). Going forward, feature enhancements and bugs fixing will also be required at multiple code bases. As we know, the life cycle of any product never touches 100%. Code merging, testing, deployments all sorts of activities come into play later on with every change.

SOLUTION

To address above mentioned problems, there’s this concept of micro web apps architecture floating on the internet for a while now. Which states, try breaking down each of the modules of your SPA into multiple self-hosted or embed-able components.

Before angular team, there was NX by Nrwl. They provided mono-repo workspace for angular.

Workspace is a single source which provides decomposition of your huge application into micro apps. This enables you to host these micro apps in a parent application or on their own. The legacy has been iframes but they have security concerns.

These days, workspace is part of initial angular scaffolding. In Angular 8, lets see how can we achieve micro-apps architecture without using any third party tools. So let’s get started…


SETTING UP MONO REPO

Install the latest angular-cli and head into your console. Use the command parameter;

--create-application=false 

to start with an empty workspace as mentioned in the help section of CLI.

Run below command to setup workspace.

ng new firstMonoRepo --create-application=false

This will create only limited set of files in the directory.

Open the project directory in your favorite code editor and view angular.json file. You’ll see an empty json object for the key “projects”.

Now go back to terminal and check how can we add an application to our workspace. Type in below command to see available options from generator.

ng generate --help

The generator provides application as a schematic to create an application.

Type in the command:

ng g application microApp1 

in terminal to create a new application with name microApp1.

When generator asks, add the routing & styling as part of the setup and proceed.

Once the setup is complete, open the angular.json file again, to view the changes. You’ll see the “project” key is updated to microApp1.

If you check the last line of the angular.json file, you’ll find the “microApp1” has also been updated in the “defaultProject” key.

Now head into the console and do:

npm start

This will start the default application in our workspace.

Default app launches on localhost:4200. So far so good…

Let’s add another app into our current workspace. Head over to terminal one more time and enter:

ng g application microApp2

Angular-cli adds the new application in the projects directory & list it under “projects” key in the angular.json file.

Let’s change the “defaultProject” to newly created app and do

npm start

As shown below, it launches the second app which we created. All good till this stage.

Now lets create the startup application which can load the two micro apps. Using the generator lets add 3rd application in the workspace as shown below.

Once startup app is created by cli, update the angular.json file by making “startup” as a default project.

npm start 

again to view this app running in the browser;

At this stage we are comfortable for adding and setting up micro applications in single workspace.


SETTING UP MICRO APPS

As all three apps at this point has similar named files as app.component, app.routing.module & app.module lets refactor some code to identify them clearly.

microApp1 code has been refactored, lets see if our changes are not breaking and how can we directly run this app from cli.

If we go down into CLI help, we’ll find ng serve has an argument with project.

So by using command;

ng serve [project-name]

we can directly launch our app. So let’s do this and run our refactored app on port 4400 by running:

ng serve microApp1 --port 4400

At this point, we can run our startup app as well on port 4200, using command;

npm start

Now that our “startup” app and “microApp1” is running, Let’s add a feature module to our microApp1. First go into the app folder of microApp1 and enter the feature-a module command:

ng g module feature-a

Then add component to this feature-a module, by running below command while inside the feature-a directory:

ng g component feature-a

This will automatically update references of you feature-a component inside the feature-a module. Lets create a route for this feature-a component in our microApp1RoutingModule as shown below. FYI — You’ll have to export feature-a component.

After updating the routes and component of feature module, try testing the route as shown below;

At this stage we can run both of our apps independently through cli.

Our microApp1 is working fine till last step, now time to host this app as a lazy loading module inside of startup app. To do this, add route in the app.routing.module.ts in the startup app.

Now if you go into the browser on route localhost:4200/microapp1. You’ll see the error “BrowserModule has already been loaded.”.

To fix this issue open the microApp1Module and change the module to CommonModule instead of BrowserModule.

Now if you go to browser, it’ll give you error “RouteModule.forRoot() called twice”.

Aha! to fix this open microApp1RoutingModule and update it to RouterModule.forChild() from RouterModule.forRoot().

Save your above changes and hit the microapp1 route in the browser. You’ll see that module files are now loading successfully. Also, you can open the feature module of microApp1 through the nested route as shown below.

Our microApp1 has successfully hosted inside of the startup app!

RUNNING STANDALONE APP

Lets try to run our microApp1 as a standalone app via cmd;

ng serve microapp1 --port 4400

You’ll see the error below in console. “Is platform module (BrowserModule) included?”

Now there’s a problem. If you change the CommonModule back to BrowserModule then our startup app will break again. To resolve above error lets inject a module, based on compile time flags from environment file. This will allow the app to work both in standalone & hosted environments.

For this, add a new key standalone: true in the environment.ts file

Location: projects\microApp1\src\environments\environment.microapp1.ts

Make below changes to choose module type based on the flag value.

Similarly, update the RouteModule based on the condition as shown below;

Once these microApp1 changes are done, open the startup app-routing.module.ts and set the standalone flag as false. This will make the app pick the right modules when running as a hosted app or a standalone app.

Try running both the commands in two different terminals

ng serve microapp1 --port 4400
npm start

as shown below:

You’ll find microApp1 is running on both routes.

In the similar way, we can add as many apps hosted inside our main/startup app. Which can run on their own as well and can be deployed with publish command individually where required.

Thank you for making this far. Happy Reading! :)

Source Code is available @ GitHub.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade