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:
- 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.
- 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.
- 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.
- 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.
- 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.
- Extensibility: NX is highly extensible, allowing developers to create custom generators, plugins, and configurations to suit specific project requirements.
- 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.