How to set up an Nx-style monorepo workspace with the Angular CLI: Part 3
In Part 3 of this tutorial, we create the passenger info and flight search feature libraries. We use the generate project tool to create the mobile booking application and its test project. Finally, we create a mobile version of the flight search component template.
Lars Gyrup Brink Nielsen
inDepth.dev Writer, Tech Speaker, Podcast Host, OSS Contributor, Microsoft MVP.
Frontend Architect at Systemate in Denmark.
Passionate about software architecture, testing, and reactive programming.
This tutorial is part of the Angular Architectural Patterns series.
In Part 2 of this tutorial, we used the generate project tool to generate the booking data access and shared data access workspace libraries with NgRx Store and Effects. We extracted a shared environments library and hooked everything up to the booking feature shell library.
In this part of the tutorial, we're going to create the passenger info and flight search feature libraries, each with a routed component. After that, we'll create the mobile booking application project and its end-to-end test project. Finally, we'll use builder file replacement to create a mobile version of the flight search component template.
Passenger info feature library
Let's create our first feature library, the passenger info feature which is part of the booking domain.
After generating the project using the previous commands and parameters, we get this file and folder structure.
This looks a little different from a feature shell library and a data access library.
After the generate project tool has created the workspace library with an entry point Angular module, it runs the commands in the next listing.
The generate project tool also removed the --no-common-module flag from the ng generate module command we saw earlier, since this Angular module will be declaring components.
Let's look at the Angular module our tool has generated.
The entry point Angular module shown in the previous listing is a good starting point. We need to set up the feature routing for our component though. This is done in the next listing.
Nice! Now we've prepared our feature library to be hooked up to the feature shell library's routing configuration.
The generated component is what you'd expect. What it'd display in a real booking application is not really important for the purpose of this article.
Let's hook up this feature to the booking application's routing by adding a route configuration to the booking feature shell Angular module as seen here.
Flight search feature library
We have one feature library left in the booking domain. Use the following command to generate the flight search feature library.
We'll perform the same changes as we did in the passenger info feature library. Configure routing to the entry point component and set up lazy-loaded routing in the feature shell Angular module.
As the previous listing shows, we've also configured the default route to redirect to the flight search path.
Take a look at our current project folder structure in this figure.
Now that we have a few routes, try spinning up the booking desktop application with npm start or yarn start. Try out the routes http://localhost:4200/flight-search and http://localhost:4200/passenger-info.
We're done with the booking domain. Let's set up the mobile booking application.
Mobile booking application
I've extended the generate project tool to support an application command that automates the commands we used to generate the booking desktop application.
Use this command to generate the application project.
So now we have two identical applications. How does that make sense? Nrwl's book mentions an adaptive layout approach where the application that's served is based on browser sniffing so that the two booking web applications are served on the same URL.
How can we differentiate components between two application projects sharing the same orchestration through a feature shell library like in this example? Read "Shell Library patterns with Nx and Monorepo Architectures" by Nacho Vazquez to learn a few techniques, or simply use file replacements in angular.json.
Let's use the file replacements technique for the purpose of our case study.
First, create a mobile flight search component template by using this command.
Now configure file replacements to use the mobile flight search component template when building and serving the mobile booking application.
Unfortunately, we have to keep the file replacement entries in sync between the development configuration and the production configuration.
We now have these file replacement configurations for the mobile booking application project.
Run the following commands to verify that it worked. You should see the message mobile flight-search works!.
Remember to lint and test our new projects to keep a tidy ship!
Well done, we now have the following application project folder structure in place.
Start the mobile booking application by running the ng run booking-mobile:serve command.
The current folder structure of our workspace is shown in the following figure.
In this part of the tutorial, we used our generate project tool to generate the passenger info feature library.
To set up routing for this feature, we added a single route for the passenger info component to the passenger info feature Angular module. We then added a lazy-loaded route to the booking feature shell Angular module.
Next, we generated the flight search feature library. Like before, we added routing and set up the default route to redirect to the flight search route in the booking feature shell Angular module.
After checking that the routes worked, we used the generate project tool to generate application and end-to-end projects for the first time. We used the tool to generate the mobile booking application and its end-to-end test suite.
To implement the adaptive layout approach that Nrwl's books mentions, we used file replacements to allow a mobile template for the flight search component.
Finally, we linted and ran test suites for the new projects and started the mobile booking application which at this point looks like the screenshot in this conclusion.
In Part 4, we're going to create two workspace libraries and two applications in the booking domain and hook up data access and the feature shell Angular module. We review how much of this is automated by our generate project tool.