Building Scalable Angular Apps with Multiple Frontends

When developing complex Angular applications, we often need to create multiple frontends to cater to different user types or channels. While these frontends may require distinct UI styles or features, they also share common functionalities. In this article, we’ll explore a single-Angular-project solution that balances code sharing and separation, ensuring maintainable and scalable codebases.

The Challenge: Balancing Code Separation and Sharing

Creating separate apps for each frontend can lead to code duplication, bloating, and maintenance nightmares. On the other hand, finding a balance between code sharing and separation is crucial. We’ll demonstrate how to achieve this balance using lazy loading feature modules and dynamic configurations.

A Real-World Example: E-Health App with Two Frontends

Let’s consider an e-health app with two frontends: a patient portal and a doctor portal. The patient portal allows patients to book appointments and manage medications, while the doctor portal enables doctors to perform admin tasks and manage medications. Although they expose different features, both portals share common functionality and are built on the same framework.

Goals and Objectives

Our goals are to:

  • Achieve clear separation between the two portals
  • Share a set of common code and feature modules
  • Enable independent building and deployment of each frontend app
  • Ensure the built package only includes relevant modules

Setting Up the Angular Project

To get started, make sure your local environment has Node.js ≥ v10.x.x and Angular CLI ≥ v9.x.x installed. Create a new app skeleton using the Angular CLI command. Then, add a new module using another CLI command, which will generate a patient folder containing the module, routing, and component files.

Creating Lazy Loading Feature Modules

In Angular, everything is organized into modules. We can create feature modules, which are typically organized by domain area and can be used to group related components, services, and functionalities together. A feature module has a root component that acts as the main view of the module. We can use lazy loading to load these modules on demand, reducing the bundle size of the main application.

Targeting Frontends via Environment Files

To target each frontend portal, we’ll create different environment files for them. Both environment files will reside under the environment folder, and we’ll use the moduleId to differentiate the patient and doctor portals.

Dynamic Routes and Menu Generation

We’ll define all routes in a single file, routes.ts, for easier maintenance. Then, we’ll set up the APP_INITIALIZER DI token to hook into the app bootstrap process. This will filter the routes and set them into the current router, ensuring only relevant routes are loaded into the app. As a bonus, we can use dynamic routes as the data source to generate menus, which will update automatically when routes change.

Applying Different Styles to Each UI

To apply different styles for each app, we’ll create separate SCSS files: styles.scss, styles-patient.scss, and styles-doctor.scss. In the Angular.json file, we’ll map the styles to different builds.

Building and Running Multiple Frontend Bundles

To build and run the two portals separately, we’ll rely on the environment configuration. We’ll add the necessary configuration into the Angular.json file and use the environment configuration to build and run each portal app.

Code Separation and Sharing

Each portal app has its own entry component, which serves as the container for child components. Each portal can have its own header/footer component and independent CSS styles. When we change one app, the other won’t be affected. The lazy-loading feature modules are built into small bundle files, which will only be downloaded to the client browser when the router is navigated to.

Conclusion

In this article, we’ve demonstrated how to build an Angular app with multiple frontends using lazy loading feature modules and dynamic configurations. We’ve achieved clear separation, easy code sharing, and independent build output, ensuring scalable and maintainable codebases.

Leave a Reply

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