Hey there Anyone availa…

5 minute read

Hey there. Anyone available to discuss some questions I have around how to best structure an Angular + NGRX app with interdependent modules in NX?

Responses:

Shoot! If you post the questions in this thread I or someone else that knows the answer will be able to help!

Hi

Well, I currently have one “app” within my workspace, with most of the code within. That app is comprised of different Angular modules, each of which handling its own part of the store and exposing actions, selectors, etc to the rest of the app

With everything in a single NX “app”, this all works fine. The root app modules loads any of the feature modules lazily when needed. Then, in turn, the lazily loaded modules load other feature modules that they depend on.

Now, I’m trying to restructure the workspace to split everything up where possible to benefit from caching, but also to be able to test using Storybook

have you read the Nx monorepo book? (it isn’t very big) It explains how to split your repo up in the exact situation you are encountering.

Happy to discuss what the structure would be once you familiarize yourself with suggested monorepo structure!

I did, a long while ago, but I’ll check it again, I’m curious if there are ideas around NGRX and cross-dependencies

I believe it talks about state, but at a high level the related feature states (and selectors efects etc) are inside a shared lib in the scoped folder for that feature.

https://connect.nrwl.io/app/books/enterprise-angular-monorepo-patterns

This one, right?

Thats the one!

Ok ok, diving in :wink:

Cool let me know if you have any questions!

I read through it all, and it does help, as I see I should go one step further in my decomposition

But unfortunately there’s not much in it specifically about cross-feature interactions and NGRX

Ok, so i guess what I would suggest is to put your different ngrx feature states into their own libraries that are scoped to the feature that they relate to.

It sounds like your actual app code is within the app itself too? And not libraries?

So far it was, yes. But now I’ve extracted almost everything out to libs

Ok awesome! That is a good step forward.

Next step would be to refactor your ngrx states into libraries.

The only thing is that my “feature” modules contain everything for their app domain (e.g., the feature-meetings module contains init, routing, store (actions, reducers, etc) for the meetings part

Sounds good yes, so here’s an example

In my app’s domain model, I have Meetings and Topics

NGRX selectors for meetings do rely on the selectors from Topics, as the denormalized version is composed of both types of entities

So it feels like I’m still going to have circular dependencies there?

My suggestion would be to make each of your ngrx feature states into their own libraries and see how it looks after that.

Yep, I’ll do that and see :wink:

This is a monster refactoring already :smile:

Awesome!

Thanks

I completely understand, I am refactoring our NGRX Data stores right now into libraries and it’s a lot (we have 4 angular apps and a bunch of libs)

You are welcome!

^^

Do you make use of facades in your workspace?

We do not right now no. but the majority of our state (in our main CRUD heavy application) is all done through NgRx Data anyway so I guess technically it is a facade?

Yup, indeed

In my app, we have different concepts, such as facades (in front of the store & used by the smart components), and ViewModels, which are types that represent denormalized compositions of NGRX entities coming from different stores) and usually corresponding to the needs of a specific smart component

I suppose that the facade should go to the extracted store library, as it is closely tied to it, but then the viewmodels should also remain there as the selectors will need those too (I’m thinking out loud :p)

Maybe you would want ot create a separate library for your view models? Say you have a feature state lib for products and you have a feature state lib for purchases if you wanted a view model that combined those two states (using selectors) you could create a product-purchases feature state lib that combines them. This way if you change something in your joined view model it wont (necessarily) affect stuff that ONLY uses purchases or ONLY uses products ?

Mh I need to think about it and see it in code. The thing is that the selector returns an instance of the ViewModel, but to be able to do that, it uses selectors coming from other modules

So for this scenario it’s actually the selectors that create the issue

Hey there!

I could finally make it work (not the whole app yet, but it’s on the way :p)

I ended up merging the store parts together in an extracted module, as they all depended on each other

So now I have n feature modules, all depending on one “store” module

can i ask you what is your final solution about the issue you mentionned above: “NGRX selectors for meetings do rely on the selectors from Topics, as the denormalized version is composed of both types of entities”? thanks

Well as I said above, I’ve extracted all the NGRX-store related code out of my different libraries and moved it into a specific library

I didn’t really have a choice as most of those modules have bi-directional relationships

thanks!

Hey Sébastien sorry I never got back to you yesterday. I am wondering if there is an opportunity to refactor your state a bit so you don’t have one monolithic store library. I’ve been doing my best to avoid stuff like that as much as possible as the dependency graph can get out of hand really fast.

No worries :slightly_smiling_face:. Well it seemed difficult to do. So far in the app, we’ve structured our store around major domain model concepts. Each part of the store handles one specific concept and relies on NGRX entity to store those. So we have a structure like { meetings: {}, topics: {}, … }. Those entities are normalized, so they only contain references to the ids of other entities, thus entities in the store have a 1:1 mapping to the database documents.

The selectors do the heavy lifting of composing those disparate entities back into nicely structured objects, using selectors from the other parts to get the entities that the current entity is linked to. For instance, when creating a MeetingViewModel, we need a meeting entity, plus 0-n TopicEntity + 1 CategoryEntity, etc

Updated: