Friday 17th May 2024
Ho Chi Minh, Vietnam

1. Introduction

Managing multiple Angular applications and libraries across disparate repositories in modern software development environments leads to significant code consistency, reusability, and maintenance challenges. The absence of a centralized structure results in duplicated efforts, divergent codebases, inconsistent tooling, and hindered team collaboration.

Let’s imagine we build an e-commerce platform that contains two Angular web apps used by internal staff and customers. The staff app and the customer app contain many similar UI components such as the product info below, which is used on the staff app – product management screen and the customer app – product detail screen. We need an approach to reuse the product info screen and the other common UI components.

Consequently, there arises a critical need for an monorepo solution that consolidates diverse projects, fosters code sharing, enforces uniform development practices, and simplifies maintenance, thereby addressing the complexities associated with fragmented repositories and promoting streamlined, scalable, and collaborative software development processes.

Popular tools like Nx and Angular CLI support managing monorepo, providing commands and tooling to create, build, test, and manage multiple Angular applications and libraries within a single codebase. We will use Nx to create a sample monorepo project on this topic.

2. Nx

NX is a powerful set of extensible dev tools built around monorepos, primarily used with frameworks like Angular, React, and Node.js. It’s developed by Nrwl (pronounced “narl”), which focuses on simplifying enterprise development workflows.

Key components and features of NX include:

  1. Monorepo Structure: NX helps structure projects in a monorepository, allowing multiple applications and libraries to coexist within the same codebase. This promotes code sharing, easy dependency management, and centralized configuration.
  2. Powerful CLI: It provides a command-line interface (CLI) that extends the capabilities of Angular CLI or other framework CLIs. This includes commands for generating code, running tests, serving applications, and managing the monorepo structure.
  3. Code Generation: NX offers advanced code generation tools that assist in creating components, modules, services, and more. It integrates with the framework’s CLI to enhance and automate code scaffolding.
  4. Dependency Graph: NX includes a dependency graph that visualizes relationships between different projects, making it easier to understand and manage dependencies among applications and libraries.
  5. Built-in Architectural Principles: It encourages best practices like the separation of concerns, enforcing consistent folder structures, and providing guidelines for scalable and maintainable codebases.
  6. Extensibility: NX is highly extensible, allowing developers to create custom generators, plugins, and configurations to suit specific project requirements.
  7. DevOps Integration: It integrates seamlessly with various CI/CD pipelines and DevOps workflows, facilitating automated testing, building, and deployment processes for monorepo-based projects.

3. Sample project

We will create a sample project to implement the example mentioned above about an e-commerce platform with the staff app and the customer app using Nx monorepo.

3.1. Create workspace and apps

npx create-nx-workspace

You will be asked to specify some parameters to create the workspace as below. With the below parameters, we will create a monorepo project with a staff-app application.

It will take some minutes waiting for NX to initiate the workspace. After that, we can access the workplace and create the customer-app.

cd nx-angular-mono-repo
npx nx g @nx/angular:app customer-app --directory=apps/customer-app

The project structure will be as below.

3.2. Create product library

npx nx g @nx/angular:library product --directory=libs/product --standalone

The product component will be created under libs/product directory including:

  • its own project.json file with corresponding targets you can run (e.g. running tests for just orders: nx test orders)
  • the name you specified in the generate command; you can find the name in the corresponding project.json file
  • a dedicated index.ts file which is the “public API” of the library
  • mapped in the tsconfig.base.json at the root of the workspace

We will add some HTML/CSS to display a product.

libs\product\src\lib\product\product.component.html

<!DOCTYPE html>
<html>
<head>
<style>
.card {
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
  max-width: 300px;
  margin: auto;
  text-align: center;
  font-family: arial;
}

.price {
  color: grey;
  font-size: 22px;
}

.card button {
  border: none;
  outline: 0;
  padding: 12px;
  color: white;
  background-color: #000;
  text-align: center;
  cursor: pointer;
  width: 100%;
  font-size: 18px;
}

.card button:hover {
  opacity: 0.7;
}
</style>
</head>
<body>

<h2 style="text-align:center">Product Card</h2>

<div class="card">
  <img src="https://www.w3schools.com/w3images/jeans3.jpg" alt="Denim Jeans" style="width:100%">
  <h1>Tailored Jeans</h1>
  <p class="price">$19.99</p>
  <p>Some text about the jeans. Super slim and comfy lorem ipsum lorem jeansum. Lorem jeamsun denim lorem jeansum.</p>
</div>

</body>
</html>

3.3. Use product library

We will create a route to each app: /product-mng which is the product management page in the staff portal and /product-detail which is the product detail in the customer portal. We can easily use ProductComponent via @nx-angular-mono-repo/product.

apps\staff-app\src\app\app.routes.ts

import { Route } from '@angular/router';
export const appRoutes: Route[] = [
    {
        path: 'product-mng',
        loadComponent: () =>
          import('@nx-angular-mono-repo/product').then((m) => m.ProductComponent),
    },
];

apps\customer-app\src\app\app.routes.ts

import { Route } from '@angular/router';
export const appRoutes: Route[] = [
    {
        path: 'product-detail',
        loadComponent: () =>
          import('@nx-angular-mono-repo/product').then((m) => m.ProductComponent),
    },
];

3.4. Start apps

Let’s start the staff app and the customer app using nx server command.

npx nx serve customer-ap
npx nx serve staff-ap

The result is that each app can display the product info which is shared by ProductComponent in the library.

Staff app – product management page:

Customer app – product detail page:

4. Conclusion

In conclusion, an Angular monorepo offers a powerful solution for managing multiple Angular applications, libraries, and shared code within a unified repository. It addresses several critical challenges faced in software development by providing a centralized structure for code sharing, maintenance, and collaboration. It empowers teams to efficiently manage complex projects, foster code quality, and streamline workflows throughout the development lifecycle.  The sample project can be found on GitHub.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top