Creating a full-stack Nx monorepo
Edit: This article by Mateus Carniatto seems more updated than my old experiment. I will be posting new ones soon :)
First of all, why a monorepo? there are many articles out there that explain why this kind of setup facilitates the development of complex applications. Code reusability and consistency are hugely improved, making visible any particular change on the system across all the dependencies, and facilitating the integration tests.
@nrwl/nx
is a tool built on the top of @angular/cli
that help us to create a workspace. with special folders for applications and libraries, along with some scaffolding to help with building, linting, and testing, encouraging the global usage of best practices and team standards.
Setting up an Nx monorepo
Nx can be installed in the following ways:
npm install -g @angular/cli @nrwl/schematics
yarn add global @angular/cli @nrwl/schematics
Within @nrwl/schematics
we have the utility to create our workspace:
create-nx-workspace mymonoreponame
This will create an Nx Workspace using Angular CLI with the Nx schematics collection. You can also add Nx capabilities to an existing CLI project using:
ng add @nrwl/schematics
Within the workspace, we will have the apps, libs, tools, with the configuration files for Angular, Nx, TSLint and Typescript:
/apps <- our frontend and backend apps
/libs <- shared libraries
/tools <- schematic and misc tooling
angular.json <- angular configuration for apps and libs
nx.json <- nx metadata
package.json <- main project info and scripts
tsconfig.json <- global compilation config
tslint.json <- global lint rules
By default, Angular uses Karma and Protractor for testing, but Nx supports the usage of Jest and Cypress. If you want to enable Jest, you need to execute:
ng generate jest
this will install the packages and update the required configurations, and we need to do it only once per workspace.
Creating a Frontend App
Adding new apps to an Nx workspace is done by using the Angular CLI generate command, with the app
schematic provided by Nx:
ng generate app myfrontendapp
ng generate app web --unitTestRunner=jest --e2eTestRunner=cypress
This will add the required folders and files, and its configuration like:
/apps
/web
/src <- Angular app
browserslist <- supported browsers criteria
jest.config.js <- Jest config
tsconfig*.json <- custom compilation rules
tslint.json <- custom lint rules
/web-e2e
/src <- Angular e2e tests
cypress.json <- Cypress config
tsconfig*.json <- custom compilation rules
Creating a Backend App
We need to use the node-app
schematic here, and optionally we can pick a backend framework like express
or nestjs
.
ng generate node-app server
ng generate node-app server --framework=nestjs
generating a backend App with a pretty similar structure:
/apps
/server
/src <- NestJS/Express App
jest.config.js <- Jest config
tsconfig*.json <- custom compilation rules
tslint.json <- custom lint rules
as you can see, Nx provides easy ways to customize the global rules when a specific project requires it and organizes our apps in a consistent way.
Creating Libraries
Now it’s time to share some code using libs. Let’s create theshared
one:
ng generate lib mylibraryname
ng generate lib shared --unitTestRunner=jest --publishable
this will create a consistent structure but this time with some new files:
/libs
/shared
/src
/lib <- library source
index.ts <- library entrypoint
jest.config.js <- test runner config
ng-package.json <- packaging configuration
package.json <- library npm metadata
tsconfig*.json <- custom compilation rules
tslint.json <- custom lint rules
the --publishable
option added some package files required to publish the built library on an npm registry. That’s helpful if another repository or project will use this library outside of the monorepo.
This library generation will also configure the global tsconfig.json
paths with the library entry point. Be sure to customize your project scope
in the nx.json
file or while you create your workspace:
From there, you can add some common components and utilities inside the @myproject/shared
library, and import them in your apps easily. You can think about how many libraries do you want to handle to modularize your project properly, and Nx will take care of the setup for you.
Nx Utilities
Nx also knows how your apps and libs depend on each other. To see the dependency graph of your project just run:
npm run dep-graph
yarn dep-graph
also, Nx provides a useful script for CI to test only the changed code on a branch. If you modify a library, it will run tests for all the apps that use it:
npm run affected:test --base=master
yarn affected:test --base=master
and finally, you can keep your Nx up to date running the following script when a new release comes out:
yarn add @nrwl/schematics@latest
yarn update
you can check all the available scripts inside the package.json
file.
Angular Console
Recently the Nrwl.io team released a powerful tool that gives a visual overview of the complete project and the available schematics to use. With it you can check deeper all the options that you have while creating Apps and Libraries, and also generating components, services, etc. You can learn more at angularconsole.com.
NgRx Schematics
Using it, I’ve been developing a custom set of scripts with the available schematics to build my Stores, Reducers, Actions, and Effects faster. Here I share some of them with my custom approach to structure them.
Root Store with Actions and Effects
Tools shouldn’t limit your taste when it comes to structure your projects, so playing with the Angular Console, I’ve been finding the right commands to use to keep my standards and have a result like:
/app
/store
/actions
session.actions.ts
effects.ts
index.ts
reducers.ts
state.ts
and I made it with three actions on the Console that resulted in the following commands:
ng generate @ngrx/schematics:store app --statePath=store --no-flat --no-spec --root --module=app.module.ts --stateInterface=AppStateng generate @ngrx/schematics:effect store/router --no-flat --no-spec --root --module=app.module.tsng generate @ngrx/schematics:action store/lang --group
you can check the detailed commits and my customizations here.
Enjoy!
Angular is moving on with awesome tools and patterns that will make our life as developers pretty enjoyable, so keep it up with the new releases!