Nx is a suite of powerful, extensible dev tools to help you architect, test, and build at any scale β integrating seamlessly with modern technologies and libraries while providing a robust CLI, caching, dependency management, and more.
It has first-class support for many frontend and backend technologies, so its documentation comes in multiple flavours.
Below is the sample folder structure for Nx with NestJS and Angular. Our principles are:
- SCAMs (single component Angular modules) for tree-shakable components, meaning each component will have a respective module. For example, a
RegisterComponent
will have a correspondingRegisterModule
, we won't declareRegisterComponent
as part ofAuthModule
for example. - Mostly everything will stay in the
libs
folder. New modules, new models, new configurations, new components etc... are in libs. libs should be separated into different directories based on existing apps. We won't put them inside theapps
folder. For example in an Angular, it contains themain.ts
,app.component.ts
andapp.module.ts
.
βββ root
βββ apps
β βββ api <-- nestjs
β βββ client <-- angular
βββ libs (1)
βββ api <-- grouping folder (dir)
β βββ core <-- grouping folder (dir)
β β βββ feature <-- nest:lib (2)
β βββ feature-1 <-- grouping folder (dir)
β β βββ data-access <-- nest:lib, service + entities
β β βββ feature <-- nest:lib, module + controller
β β βββ utils <-- nest:lib, things like interceptors, guards, pipes etc...
β βββ feature-2 <-- grouping folder (dir)
β βββ data-access <-- nest:lib, service + entities
β βββ feature <-- nest:lib, module + controller
β βββ utils <-- nest:lib, things like interceptors, guards, pipes etc...
βββ client <-- grouping folder (dir)
β βββ shell <-- grouping folder (dir)
β β βββ feature <-- angular:lib (3)
β βββ feature-1 <-- grouping folder (dir)
β β βββ data-access <-- angular:lib, service, API calls, state management)
β β βββ feature <-- grouping folder (dir) or lib (4)
β β β βββ list <-- angular:lib e.g. ProductList
β β β βββ detail <-- angular:lib e.g. ProductDetail
β β βββ ui <-- grouping folder (dir)
β β βββ comp-1 <-- angular:lib, SCAM for Component
β β βββ pipe-1 <-- angular:lib, SCAM for Pipe
β βββ shared <-- grouping folder (dir)
β βββ data-access <-- angular:lib, any Service or State management to share across the Client app)
β βββ ui <-- grouping folder (dir) (5)
β βββ utils <-- angular:lib, usually shared Guards, Interceptors, Validators...)
βββ shared <-- grouping folder (dir), most libs in here are buildable @nrwl/angular:lib)
βββ data-access <-- my shared data-access is usually models, so it is a lib
βββ ui <-- optional grouping folder (dir), if I have multiple client apps
βββ utils <-- optional grouping folder (dir), usually validation logic or shared utilities
βββ util1 <-- lib
βββ util2 <-- lib
- lib vs grouping folder (dir)
- a dir is just a directory.
- a lib is generated by using Nx schematics
api-core-feature
: this is the CoreModule that will include all initial setups like Config and Database Connection etc... and importing other Modules. CoreModule will be imported by AppModuleclient-shell-feature
: Same idea as NestJS's CoreModule. This Shell includesRouterModule.forRoot()
client-feature-1-feature
: This can either a dir or a lib.
- If this feature only has one Routable component, it is a lib.
- If it has multiple Routable components, then it should be a dir. For example:
βββ feature
βββ list (angular:lib e.g ProductList)
βββ detail (angular:lib e.g. ProductDetail)
feature
usually contains the ContainerComponent and the RouterModule.forChild()
client-shared-ui
is a little tricky. The general recommendation is to NOT grouped stuffs by type likecomponents
,pipes
etc... into a single module but because these are shared, it is easy to get quite messy if not grouped by type. This is your call. We prefer to have a Single Component Per Module (SCAM) for each angular library.
This structure is proposed by my friend Chau Tran and I am applying it for my latest project!
Following the above structure will bring three advantages:
- Consistency: eliminate mental overhead when we don't have to think about where to put what in a big repo having from two apps and above.
- Promote Single Component Per Module (SCAM) + Buildable libraries to get the benefits from the nx affected commands.
- Prevent circular dependencies issue.
data-access
:Βdata-access
Β can import otherΒdata-access
. But never import itsΒfeature
Β . For example:Βuser/data-access
Β can import fromΒproduct/data-access
Β but it will never import fromΒuser/feature
feature
: can only import its ownΒdata-access
or the globalshared/data-access
. For example:Βuser/feature
Β can import fromΒuser/data-access
Β but never fromΒproduct/data-access
.util
: Utils can be shared acrossΒdata-access
,Βutil
.
@Benny739
Not sure what you mean by "smart guards" or why they can't reside in
libs/api/feature/utils
orlibs/api/shared/utils/
.Why couldn't you include services shared between features in
libs/api/shared/data-access
?Why not
libs/client/shared/ui
?Why not keep these services under their respective lib domain directory under
data-access
and just reference that from your other domains?