Nx After Dark: Extracting a shell library from an Angular feature

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello welcome to nx after dark it's very dark in denmark very late just spending this final time of the the final hours actually of this week we're going to do something fun we're going to be continuing on our case study of the angular 2 of heroes routing tutorial and the past few episodes i think i extracted some feature page libraries from this single project angle application the two of heroes routing tutorial which has several features and let me share my screen here again and we can take a look because it's all open source right here on github my profile lazydk nx angular 2 of heroes is the name of this repo post it here in the comments so hopefully you can find it yourself and into this description once i once i remember to do so um yeah that's another topic yeah let's let's see here so this is the repo we have this one app to a fuhrer's app but as you can see there's not much left now i did remove some additional stuff since last time i recorded and actually let's try to fire up this uh sorry the depth graph the dependency graph of [Music] nx because this is a nx workspace now even though it started as an angular cli workspace so here are all the projects by now the two of heroes app we have an admin feature page so it's a feature library in the admin scope grouping folder domain whatever and it's the page feature library so we also have a login page feature for the off domain we have a heroes page feature we have a crisis center page feature and each of these then uses some shared libraries as we can see even currently that the app itself uses a shared ui library with navigation components so just to show you um since last time i think i extracted out this this page not found component i created a scam for it um i extracted this route animations to slide in animation to this library as well and is there anything else new no naruto that might have been it that might have been it so now in this app routing module we have this com or sorry the pop-up outlet so not the primary router outlet but in the pop-up we have this compose message component which is also in the shared ui library for dialogs we have the admin feature we have the crisis sensor feature which is also in a feature page library and we have the default route here redirecting to superheroes so where might that be and i don't know whether it's made this way because of demonstrating something in this router tutorial of angle it probably is but you see we don't have any routes for the superheroes and the villains defined right here in our app routing module but that's because the modules are actually imported directly here so there's no lazy loading of the heroes feature page see there's no heroes up here this is a feature module but it also contains routes which it shouldn't at least not that many and the same i guess for login yeah so if we go and take a look at this heroes feature page module see that it has its own routing module and this is the reason we see right here that we both have heroes heroes superheroes and superhero prefixes to the rough paths in this feature which is kind of strange but it wouldn't be easy to it'll be kind of difficult to lazy load this because they have four different route patterns but it would be doable but that's something for another day today i actually want to but just yeah just understand that when we put the modules right here and imports they are eagerly loaded so they will be part of the the main chunk of our application so it's two additional features that are loaded every time the application is booted up and a good rule of thumb is lazy load everything even if it's the default page people are going to visit the app on different pages not only the default page so so why load the default page if you're going to some other feature most of the times anyways we will be looking at i think we're going to look at the crisis center feature so let's find that one it's here yeah so this is the crisis center feature page module and you should see that this is the one we're routing to here a lazy route path so every route that begins with crisis center is going to lazy load this module by using this import path and this import path is defined in the ts config basin a base json file right here it's a path mapping so it'll be in compiler options paths and what was it again crisis sensor right so one once we import from that path it will map into this path in our workspace so uh not apps but libs crisis center feature page source index th ts so that's the barrel file or the public api of this library and the nx workspace linting rules will prevent us from making deep imports beyond this public api or barrel file so this library is currently only exporting this feature module right here so that's the interesting one for today we're going to because we just stuffed everything in here uh in the first episodes we took the everything from the crisis center folder in the original app project there was a crisis center folder right here and we stuffed it right down here without changing uh much if anything at all but of course one feature should usually not be in just one library so there's a feature library right but i'm talking about an angular feature as in the whole part of the application the whole domain or sub domain or bounded context whatever you want to call it or a page of the app everything about the crisis center that's an angular feature and we usually need more than just this one library for that but today we're going to look at a very neat pattern or yeah it's a pattern and there's a few variations it's called see if i can find my browser here it is it's called the shell library pattern or actually yeah the shield library pattern there's three of them this is an article i offered together with nacho he's the main author and i guided him we came up with some ideas and concepts and we are yeah i very much recommend this article by the way it should be in the youtube chat and i'll put it in the description at some point as well when i remember um oh if you if you happen to google this uh you'll end up on probably end up on the medium version but that's the old angle on depth block you should go to in-depth.dev to find the real one and the most updated one so this article introduces first the narwhal feature shield library that's the one from the enterprise angular monorepo patterns book and the second one scroll down here we'll look at some more soon but the second one is come on it's a long one here it is the manfred steyer shell library so manfred is really into domain driven design and he proposes a shill library per domain which makes a lot of sense and it makes it's more flexible than the first one which is this now all feature shell library where you have one shell library for every app just one but with the stayer manfred steyer variant you can have one per domain and domains can be shared between applications but that's not always enough so as nacho and i came up with the third chill library pattern and it's called the composite shell library this is the most flexible one of the three because here let's see if we can see this or we can see this visualization where we have two apps in this example app or workspace from the oracle it's the narwhal airlines web app and the mobile app and the web app has two domains booking and check-in but there's a composite feature shell library for web booking for web and one for the check-in for web and it just happens that the mobile app also has a shell library for booking but the mobile one and one for check-in also the mobile one so what's different why could they not just share them as the with the manfred steyer shell library pattern well here we see that in the check-in domain or bounded context the web the web app is going to have a ticket finder feature and a check-in feature while the mobile app only has the check-in feature so its composition on the domain level and the application level in the mobile app in booking it only has the seat listing feature the mobile one that is because there is another seat listing feature library here that's the one for web so we created a specific one for mobile for this app and the web app has two features in the booking domain the passenger info info feature and the seat listing feature i hope this makes a little sense um because that's the whole purpose of this this pattern the composite shell library pattern it's the most flexible one um and i mean you can use either one but this one is is useful for certain cases where we want to create a special feature for a special app like and use the normal feature for the other apps maybe so we can orchestrate on the domain level per application if we go and see the similar diagram for the other patterns or the other variants of shell libraries we'll have the manfred steyer one it's here so here we also have two apps the novel airlines admin web app and client web app so admin and client for the regular users so the admin web app has two domains the booking domain and the check-in domain so it imports the booking shell library and the check and shell library booking has passenger info feature and the seat listing feature check-in has the ticket finder feature and a check-in feature but the admin web app does not have the flight tracking domain there's no orange line dependency graph here from the admin web app and to this domain or the kind of entry point to the main is this shell library the flight tracking shell but the client web app has the flight tracking domain these two features the flight search feature the flight details feature it also has this check-in domain so these two apps are sharing this domain with the same routes and the same features and that's where it's different from the composite shield library that they have to share the same routes the same features they're sharing orchestration through this montford style shield library per domain one per domain the app then imports however many shill libraries or domains it wants to use the original one from the narwhal book the novel feature show library is illustrated like so so in this example we have three apps the booking web app the booking desktop app and the booking mobile app they all share one booking feature shell and it orchestrates exactly the same routes and features from two domains the booking sub domain the shared seed map sub domain so since they all share the same features the same route same routes the difference must be in the application projects and they are so uh we're pretending here that or in the use case here is it's an adaptive layout so say it could be browser agent sniffing to say do you need a web this like a desktop layout do you need a mobile layout or do you need a general web layout or tablet whatever uh or they could be bundled and published in certain ways that are specific to the platform this could be the desktop one could be an electron app for linux mac and windows the web app could be a progressive web app and the mobile app could be an ionic app or some other hybrid where that may be published to the app stores so they could share the same features the same routes would that make sense you might think no but if you come to think about it what about something like slack or discord they try to have the same features on each platform so that might be a good use case something like spotify is also going back to sharing a code base maybe not exactly the same routes features um on all platforms but i i bet they wish they had or well they they are adapting to changing requirements and changing teams and new discoveries scenario rather than having three different platforms with three different code bases they're going back to trying to share the code base and sharing the features between the platforms so that might make sense in some use cases so this is a very valid pattern this variant the the one we're seeing now is the narwhal feature show so yeah you should get familiar with all these three variants of shell library the shell library pattern for an nx and mono repos so that we can decide which one is the best for our use case and i'm trying to figure it out myself as well let's have a look at the app what's the best for our use case so we have one app right just one app so right now it might be good to start with just one now all feature shield library on the other hand we could have either a manfrotto style shell library per feature or domain whatever we want to call it so one for admin one for auth one for crisis center one for heroes that makes sense even when we just have one app as we can see here we could create one for each of them and moving on to composite shell libraries well that only makes sense once you need to vary the features the feature composition and orchestration per domain or per app and since we just have one app all domains are hopefully for that one app once we have multiple apps we might decide so which one do we need now can we can keep using the novel feature shield library or the manfred steyer shield library or co2 suite switch to composite shield libraries i think i'm going to go with the manfred steyer shield library today so for this app we're going to look into the crisis center feature finally after this 20 minute long discussion i hope it was interesting and you can learn more in that article by not your vasquez so back to this crisis center feature page library which is currently just a junk library for everything related to the crisis center we have this this one module that is exported by this library it's the crisis center feature page module which is a conventional name based on the library name right it's in the crisis center grouping folder or domain grouping folder it's the feature it's a type feature library and it's the page so this domain should have just one root level page well that's the idea let's see if it sticks if it fits for this domain okay what do we have we have four components they are all declared in this one module it seems we have a routing module for the crisis sensor features and we are importing common module and forms module so they may or may not be used by this either one of these four components or all of them so well first thing is we actually need a different library now we need a shell library for the crisis center so let's start by generating that so i'm using the nx console running the generate and then searching for the novel angular library schematic it should be called feature shell you might i mean i'm using the conventional library type feature here but this is actually a special one so you might even prefix it which is shell gel crisis center but since we're already in the crisis center grouping folder uh you don't have to include this name and i don't want to introduce another type of library just for the shell at least not right now so i'm going to prefix it with the feature type so it's going to be called the crisis center feature shell module straightforward right yeah do we need any settings here we need the tags we haven't added the linting rules yet the workspace linting rules but let's keep adding the tags as we go along and we'll add those linting rules in another episode i don't think we even have eslint right now since we started with the angular cli workspace which was still using t eslint okay the scope is crisis center the type is each year generate this library see what we get it is feature shell library oh and before i forget i one thing i also changed was i added these testing settings [Music] here so i configured the test bed there are these new options on tear down you can destroy after each this is should improve performance of testing modules i think it was introduced in a recent version of angular like version 12 something and especially with karma it's leaving behind the styles of every test so they're just chunking up dom elements and might be interfering with each other and the on destroy methods of all the modules and services things like that might not even be called in certain circumstances like root modules are provided in root services and the modules which also have on destroy hooks actually believe it or not uh so yeah this this should be the default i expect it will become that at some point and even if you're using jest where the style issue is not an issue you can still get the benefit of actually calling the hooks and tearing down some resources like subscriptions or allocated memory whatever and the other one is i'm defaulting to running or auto detecting running the change detection automatically on component fixtures by default now since i'm almost always using this option i'm adding this to my default configuration here and i might overwrite it to false if i need to be very specific about the timing of change detection to set something up before or very carefully control the change detection after changing something most of the times it's very nice to have it automatically run in test it doesn't always work but for some cases which is nice because no one wants to play the framework and call change detection after every single change in the test that's just boring waste of time until the point where you need that control of the timing yeah so i'm changing that in this new project we also need to change the readme file so this is the um crisis center so it's not a feature shell it's a mount for the style shell um so it's just this domain shell basically what else yeah we have the shell module we're going to keep that but i don't want the common module unless i need it so i'm going to remove that yes good so i'm going to commit this uh usually i always create pull requests uh but yeah since i'm the only one working on this repo let's just go with regular commits and push them to the main branch um i don't even think we set up a ci workflow yet so no pull requests don't make that much sense so what are we doing we are adding something to our adwords generate crisis center [Music] feature show crisis center shell uh library there we go there we go we're on the way to starting to structure this feature better it's the second library in this crisis center domain so that we don't have a single one the junk library for everything so what should be in a shell library well first of all a shell module so what's in the shell module is the next question yeah it depends on the type but it could have feature level or root level configuration and initializers it could have routes for the specific feature or the top level routes for an entire app or the top level routes for the domain it belongs to and oftentimes when it's the domain feature or domain shell module such as the two variants this manfrotto style variant and the composite shell library variant [Music] these two types will have usually have a shell component or they will the shell component will have a scam so it'll be shell module or even shield scam why not um but let's see what we already have in what's currently called the crisis center feature page module and that's something we cut out and pasted from the the app to a heroes app originally so what belongs in this shell module routings routing for sure so let's go to this router crisis center routing module and let's see yeah i'm wondering can we paste that over to our new shell library but actually no we need that we're going to probably need that shell component but i think we already have something like that in this feature but it's not called a shield component it's called the crisis sensor component so this is kind of the page module or sorry the page component for the crisis center uh if we go and look at it we'll probably find that it has a router outlet and most likely not much else let's go look at its template in fact yeah look at that a router outlet and a title crisis sensor so this is a shell component so let's keep that name and let's start by yeah let's extract starting by copying over these routes importing the routes type and the name crisis sensor routes i'm going to leave out the shell component for now so taking one step at a time now we need this crisis center component but we also need the imports and exports here router module import from angular router and we're using the for child which means that in the application we're going to have the application project we're going to have four route that points to this shell module so that the shell this whole feature is lazy loaded so this is the first step and now we need this crisis center component that is still in the feature page library let's find it where are you this one okay good so i'm going to cut that into our shell feature library pasting it here there it is crisis center these three files and now we wish we had a scam so we're going to have to create one ourselves crisis center module ts and creating an energy module crisis center module is going to declare only the crisis center component which should be in this path anymore here it is and so this is a routed component only so we're not we're not going to export it that doesn't make sense it's it's only going to be routed so it's not going to be in any template of another component but we have to see whether we need some imports so going back to this opponent the crisis center component which is actually a shell component let's see what's needed for its template so it has it has an h2 element that's a native one so we don't need angular modules for that but this one the router outlet we do need the router module for data now we have access to this router outlet directive yeah good that's a scam a single component angular module for the crisis center component which is a shell component so oftentimes i would call this shell module and i would call this component shell component but let's keep the name here and it's perfectly fine you can use your own names and this is a better name even but yeah why not so now to to route to this crisis center component we have to import its scam so the crisis center module and the crisis center component there we go that's the first step so refactoring i move gel component gel a and next up is our application should now route to the shell module that we just created instead of the page feature which we were using before so instead of feature page we're going to use feature shell or we might need to restart the typescripts language server and it'll just take a second and now hopefully it's happy let's look at autocomplete yeah it is very good so now we have lazy loaded the shell library of the crisis center feature or domain but it will just show this empty shell which is why it's called a shell library it's the shell around this feature or it's the page or yeah whatever you want to call it it's just going to say crisis center it's going to have a router outlet so to render anything any routes in this nested router outlet we're going to have to add child routes to the route that is this is the top level route in the domain there's another top level route in the application which is routing to this module this module is just then going to route to the components or the routes that are being rendered by the shell components router outlet this one we saw before so yeah nested router outlets a router outlet inside of the router outlet that's in the app component right we see it right here okay so we need to add child routes so let's go back to the routing module we had this one the crisis center routing module and please feel free to ask questions if this is getting too complicated and i'll try to explain it better it's it's an advanced topic but one that you are going to use all the time once you get familiar with using it so yes we have all these sha components well yeah this is kind of interesting so this is the two of heroes routing tutorial so it has basically every feature of the angular router stuffed into this application so we see nested routes inside of nested routes that's kind of funny and yeah notice that we have an empty path route right here it's kind of interesting but it does have a component and this means that this component must have that router outlet so once we have another level of listing nesting here this crisis list component must also have a router outlet otherwise these routes its child routes wouldn't work so let's just verify that so that i'm not assuming things about angular that happens from time to time no here it is so this is the third nested router outlet the grandchild router outlet okay so let's take them one at a time we can't begin with the innermost so we're going to have to start with this crisis list um so where does this component the crisis list where does that belong and now we can yeah basically this is a good candidate for a separate feature library the crisis list but yeah it's always a balance of not getting too granular but not having a junk library either with everything stuffed inside it so i see the home component that might be a feature i see the detail component that's most certainly sounds like a feature a separate features a separate feature library but what's in the crisis list it seems that both of them yeah they are going to it's going to be either the home component or the detail component in that router outlet area so there's probably something else inside of the template of the crisis list a list of crisis maybe let's see let's see yeah the router outlet so this is going to render the home crisis home or the crisis detail component depending on the active route but up here we also see that we have a crisis list component or sorry the crisis list the list of prices here they are all the crisis from the crisis service we're looping over them and then we're adding a link to each crisis and once you click that it's going to be shown in the router detail component right here okay so yeah i'm wondering i just had something disconnect in my docking station seems that i'm still live let me know if you can't hear me any more or see my screen and i'll try to restart some things but here's my editor again hopefully you can see it now again and yeah so i'm i'm sitting here wondering should i create a separate feature for any of these i mean the shell shouldn't contain much because it's only the common parts of this whole domain the common parts of the crisis but we could argue that this crisis list is currently a common thing for for this whole domain hmm yeah so also thinking about the future of this app maybe we don't always want to show the list of these prices and but maybe we don't want to make assumptions about the future either right so it's a tough tough decision but most strongly i feel that i don't want more components in my shell library than the actual shell component and yeah so instead we're going to add another feature library but first let's see what did i change just closing some of this what did i change i changed the import in the app routing module yeah route to shell library there we go so we need another library we need another angular library from the narwhals nx angular library generator it's going to be called it's a feature library so that's the prefix of its name it's going to be in the crisis center so this follows structure up here it's going to be in libs because it's a library so it's going to be in the crisis center grouping folder and it's going to be called feature list and we need the tags the scope is crisis center height is feature generate this library please nx thank you for that and i have to turn this if you're organized and save i have to turn this off because i want to copy this testing setup again and these first imports have side effects ordering matters i have to import the first one before the second one but alphabetical sort would put them in the other order so that wouldn't actually work so yeah copying this to our new library setup for its tests here and now i can add it back this setting for my editor going to change the read modes this is the wrist feature presses yeah that's good enough what else so what is generated for us a crisis center feature list module yeah i tend to keep these conventionally named modules except i don't want them to add any metadata before i need it so this is good generate list feature library let's face this list feature library and we're going to take that list component and once again we're going to need a module for declaring it so we're going to create a scam access list module cs this is an energy module it declares this crysis list variable import man that worked to save a few keystrokes huh yeah oh because i didn't add the class prices list module there we go so what's wrong with the component it's probably missing some modules to be able to do something in its template so let's look at the template which module imports do we need router outlet so we need the router module what else mg4 so that's the common module so we didn't need that in here anything else router link that's also from the router module async pipe is in the common module class binding doesn't require module template expressions yeah that should be good so why is it acting up let probably just vs code i'm going to reload it spinning everything up again and seeing whether it complains now still complains i'm not happy about that oh oh okay so it's because of broken imports yeah well this is actually great because structuring our application into all these libraries is forcing us to think about our architecture and where everything belongs so for example where do we have the crisis here in the page module so this is a shared domain object or excellent domain entity right so it doesn't belong in the page feature library it should be in a shared library at least shared to this domain so so i don't mean share it down here because that's shared across domains in the application or maybe even across applications if you have multiple of those but where does it belong then and this is where we need another we need a non-conventional library type at least one that's not strictly defined in any normal resources i have read or it might be mentioned but not defined very well well first i need to i should definitely uh commit these changes yeah let's do that first so once we get that component running um we this this feature list module is the entry point of this whole library it's the only exported class so here we need to do everything you need you need to expose everything you need from this library so it's going to be the crisis list module there we go so once you import this entry point module from this library the feature library you're going to have access to every thing defined in this crisis list module which is a scam meaning you can now use the crisis list component and we're probably going to have to export that component as well to be able to use it in routes or maybe the route should be specified here yeah yeah that's a nice option i do that myself actually yeah we'll do that uh in a minute once we figure out where to put that crisis type and other things okay so um move what are we doing here move crisis list component to list feature good see if i can roll back to my train of thought we were trying to find a place for the crisis domain entity business object whatever you want to call it so let's look at the libraries we currently have we have a feature list library that's not where it belongs the shell definitely not there the page feature library not there either so we have to generate a new library and it's going to and yeah you can see that you can't be afraid of libraries and projects uh when working with nx at least not when you're using it efficiently to define your architecture and of course don't get we shouldn't be getting too granular because that will be a mess but once we have a decent amount of libraries the nx tool chain can help us depending on which features from it we're going to use such as incremental build the affected command for intelligent tests and builds and deployments and lensing and all of that goodness oh and also of course the the build cache the nx cache which can be either local but also distributed through nx cloud or on premise one okay generating another library it's going to be in the crisis center directory and let's fill out the tags here scope this crisis center and so what is this library it's a domain library and it could be domain of isis but we're in the crisis center so i don't know we probably just need one domain library for now so just call it domain the prefix can be the name the full name of the library as well because we're inside of a grouping folder the name of the library will actually be something like crisis center domain which is a good descriptive name [Music] some call them type libraries some might call them i don't know interface libraries we call them the main libraries we have the interfaces of our domain entities or business entities and we might have some pure functions as well or we might have some this is an anemic interface but we might have some rich models as well the main models that is anyways this is this new domain library we're generating that and need to remember to set up the tests uh configuration i should really be creating a workspace generator for this but that's a good topic for another episode right [Music] testing and i have to turn off this organize and save temporarily here it is saving and i can enable organize and save again i'm going to change the readme file so that it says prices center domain ice and it has a module the domain library shouldn't have an angular module it's a typescript library so we can leave this barrel file empty for now like so exporting an empty object and now we can say we're adding something so it's a feature commit generate crisis center domain library and now we're ready to locate this crisis here it is this crisis interface going to be cutting it and pasting it into our domain library into the lib folder there we go and we're going to export that right here nice and once i have generated a library i need to restart the ts server so now well let's commit move crisis entity to the main library or just domain i don't know yeah so now where did we need this we know that we needed it in the crisis list component so there it so also import that's not a good import so let's say add to heroes crisis center domain there it is right let's just check yeah it's exported nice and now we need the crisis service so where does that belong well first let me just update import and now we need to look into this crisis service where is it currently and where does it belong here it is and it also needs to update its import center domain like so i'm going to update imports changing it to single commit okay so what is this service doing it has some state behavior subject it's using a message service or it's importing it but not actually using it it's kind of fun uh you can get a crisis we can get all the crisis and we can add crisis or a single crisis yeah okay so it seems that yeah it is only using this mock crisis so that we don't need a back end for these prices yeah hey corbin nice to see you corbin crisis sounds scary yeah it is let's see which crisis we have we have a dragon burning cities we have sky rains great white sharks a giant asteroid heading for my screen here so we can see it dragon burning cities the sky rains great white sharks a giant asteroid heading for earth and procrastinators meeting is delayed again what a crisis huh typical day in california yeah exactly must be and what are we working on yeah we are working on uh of course and oh word where did i put this ah there it is so we're working on this open source repository i took the two of heroes routing tutorial from angular i o because it has a bunch of angular features um like that was a cli that was an angular cli workspace so i converted that or migrated it to nx in one episode and then i started taking that application project and splitting it splitting it into features feature libraries but that was just right now they are kind of junk libraries with everything in just one library so that's not much better um so and you're from california yeah yeah no hard feelings about uh the typical day in california yeah so the next step from here what we're doing today is we're actually going to introduce a shell library and this interesting article by nacho vasquez and myself is explaining with code examples and visualizations the three different variants of shield libraries there's one by now wall called we call it the narwhal feature shell it's in their book about angular enterprise monorepo patterns or whatever it's called we have the manfred steyer shill library um and we have the third variant which is the composite shell library which is a concept that nacho and i came up with to have maximum flexibility and so i explained them kind of earlier in this episode and we decided to use the manfred steyer variant for our application okay so uh another import that needs updating but we'll get them all eventually this will be an amend commit okay our crisis our crisis service so it's a state kind of a state service with a subject right and it's it's not communicating with the backend so it's a fake service right now actually so where does that belong we have now seen a domain library we've seen feature libraries we've even seen page and shell libraries which you might define as its own library type but right now they're defined under the feature type and what else have we seen we've seen data access and ui libraries as well so a state state management service of some kind um will usually be in a data access library so this is probably only used by in the crisis domain this crisis service but it will most likely also be used across the features which is exactly why we need to extract it to a data access library now so let's do that let's generate library we've done that several times by now it's a data access and that's the type so i might give it a name so it could be data access price crisis but since we're already in the crisis center grouping folder the crisis domain crisis center domain i don't care to give it a specific name unless we need several data access libraries in here and we don't right now so let's stick with this scope is crisis center these are our tags for this library and the type is data access generating it and i need this wonderful testing setup and to use that i have to turn off my organize and save feature temporarily copying in this wonderful testing configuration here saving it now i can re-enable my organize and save from typescript hero the extension and what else do we need to change the readme file so this is the crisis center data access but what's in here a module this is data access libraries that's probably going to contain services maybe some functions class-based services mostly so most likely we won't need any modules unless we're here using indirect store and then jrxfx which we're certainly not going to use um i would i prefer ndx component store instead um these days so we're generating generate uh crisis enter data access library there we go and now we can take this crisis service and it's using these mock crisis so let's take them as well we'll cut them out and put them right in here in the lib folder of this new data access library so we need to export definitely this crisis service and i need to restart my typescript server because it generated a new library which adds a new path mapping to my root type configuration so visual studio code is not watching that i guess so um yeah maybe if i did it manually down here added this path mapping it might detect it i'm not sure but it doesn't so yeah let's verify that our imports are valid now the relative ones the mock crisis yeah we have that right here and the crisis is now from this domain library good same thing here the crisis interface is from this domain library good seems like everything is all in order in this library so now we need to find the places where we're referring to the crisis service so that is the case in this crisis list component let's see if we can auto import this this missing import no we cannot let's copy this one and say beta access autocomplete here it is the crisis service very good and now everything seems to be in order inside of the crisis list component but let's also for good measure go into this crisis detail resolver service and update both of these imports oh auto import is working nice this one yeah there we go oh this one didn't work out well um import from heroes crisis center data access crisis service nice organized imports that's what i like and everything in order here let's make sure if we have updated all the crisis imports ah this one didn't yet we'll fix that but very good very good both crisis crisis service to data access yeah and now if we had some workspace lint rules in place we would need to make sure that it's a valid import um so for example this feature library can import from data access yeah that's a valid rule that i would have in my workspace we're going to add those at a later point i wonder what else it thinks is wrong oh now it's happy again very good i see a question in the chat alexander hello do you plan to provide the crisis center at route or inside crisis center shell well let's see how it is provided already as in this app i didn't define it so it provided in brood and um okay so i've noticed that not everyone is has the same mental map about how provided in root works so i'm just i'll try to explain it here provided and root does not mean that let me share my screen and i i suck as at switching screens okay so here it is crisis center or the crisis service is provided in root and what does this mean what it does not mean is it does not bundle this in the root chunk the main chunk our our eagerly loaded chunk of the application that's not what it means to provide and root provided in root means that even if it's a lazy loaded service because it's used inside of a lazy load feature it will be a root level provider so it will be a singleton there will be one instance per root module which usually means per angular application that is bootstrap or in the case of angle elements there will be one per angle elements which is kind of funny if it's micro front ends one per micro front end but yeah usually most times it's one per it means one per application so application wide single singleson but it's perfectly fine to have it inside of a domain or a lazy loaded feature here this crisis center we could yeah i know the confusion about feature libraries and feature modules and angular features so yeah okay so let's say crisis center let's call it the domain then crisis center is a lazy loaded domain the crisis service is only used inside of the crisis center domain even though it's lazy loaded everything in here is lazy loaded we can it's perfectly fine to provide this crisis service in the root module or the root module injector actually so how do i plan to provide it just like so which was already done in the router tutorial but it would as things are right now you're right i could have provided it in the um the shell module right here but so usually you have two options for this one you could say um provided in center feature shell module but that would be a circular dependency so instead we should remove this provider option and we should add it here in the old school way of having um providers in our module so here it would say crisis service but um the downside of this is the crisis server service would always be included in the first bundle of this domain the crisis center domain because now it's and yeah worse than that now it's not a tree shakeable provider anymore it will always be part of this shell bundle where as if we have provided in root now we have a tree shakeable provider so if no other parts of our applications are using this crisis server service it will not even be part of any bundle but when one or more features are using it it will be added to those the code will be added to this chunks and shared between them somehow using webpack and angular magic i hope that kind of makes sense so yeah just keeping it provided and wrote let's go back to the crisis list where we it's not even where we started but it was the the next step in defining this shell library for the crisis center so the crisis list component is now able to import the crisis center from this data access library okay if you provide the service in root it's possible to use the service in another domain yes except i would add linting rules workspace linting rules saying that and and this is why we're adding the the tags let's go find the tags of this library so the crisis center data access it has two tags scope crisis center and type data access so once i add eslints to this workspace i will set up now the workspace lint rules and i will use these tags to define architectural boundaries and rules about valid dependencies so one of them will be um probably something like only a feature library can import a data access library or maybe other data access libraries can can also import data access libraries and the second rule applicable here is only scope crisis center can import libraries that have the scope crisis center tag and in this way we would prevent other domains from importing anything from this crisis centered data access module so this is an example of where nx is helping us once we add the workspace lint rules which are usually there when you generate an nx workspace but this is a migrated angular cli workspace which was using tslint and i just haven't gotten around to setting up eslint yet that's going to be quite a task because i need to add configurations to every single library and i'm creating more and more libraries now so it's going to be fun and tedious i see here i forgot to add type domain tag to this crisis center domain library we created not too long ago and everything else seems to have a nice tags except for the original project here two of heroes app a scope two of heroes i don't know what's the scope of your lap the type is app so we could set up rules for that as well saying um app projects can only import shells for example shell libraries if we have a shell library type we don't but we have instead our shell library has the type of feature so we can say the app can only import feature libraries for example which is another reason for maybe you wanted a shell type so that we can say apps can only import shells shields can only import features and data access and whatever we see is reasonable ah i'm glad it makes sense alex thank you for your question let's see where we were we're at the crisis link component and now seems to have everything its needs it will most likely compile with the rest of the application missing tags very good so now that we have our crisis list component working with a scam and a feature module and i was just wondering should this have been a ui library but no this is not a presentational component it's using it's injecting a service another presenter service so it's not a presentational service it's a state service or something like that right so which makes it a smart component um of some sort but yeah i guess it's a mixed component because it's also rendering uh this data so yeah it's a mixed component not a not a container component or presentation component it's a mix of both so but yeah it it has it's a smart component it's injecting a service and it's it's consuming the data of that service so it should be in a feature library ui libraries can contain on the other hand ui libraries can contain presentational components presenters so that's presenter services which are presentational services it can also contain directives and pipes and maybe a service used for presentational purposes presenters is one but i think we have i think we actually had one down here we have a service for no here in the dialogues ui library we have a dialogue service this is a presentational concern so that's why it's in this ui library okay so the crisis list component is inside of a feature list and it may look like this is an awfully tiny library it only has one component basically but remember this is just a tutorial the real real app might be a lot more complicated than just this one list it might have a data grid and several sub components and and so on even even this one could be split into container component and presentation component maybe some child components presentational components and and so on so it's a pretty it's pretty simple example so it should um it's more like an early application prototype or something like that it's it's definitely not a real world application this two of heroes router tutorial yeah so let's go back now to our shell library and now we can start adding our first child route so let's go back here to the original routing module and steal it from here the crisis list component but i won't include its its child routes so i will only add the rob for the crisis list component for now and to do that i need to import something from add two of heroes crisis center feature list autocomplete crisis center feature list module oh and the component hopefully no did i not export that feature list index ts now okay i need to import that component so that i can route to it here it is certainly i also need the module so i need to import that here feature module so that i can route to this component inside of that module this tells us that when we do this the crisis list component and everything inside of this module becomes part of the bundle of the shell library so even though we have them in separate workspace libraries they will yeah based on my understanding of angle on webpack and all that they will share a bundle a shell the crisis center shell bundle because this is not lazy loaded so yeah i would i would actually do um sort of this route i have like so instead right import heroes what's it called the crisis center feature list and module like so i would create another lazy loading boundary here maybe unless it hurts performance but yeah my point is we will be chunking everything um does that make sense yeah it might it might make sense right now because the this list of crisis is always shown on this crisis page or inside of this shell so yeah maybe it's good enough for now but but usually in a real application you might even start to add another lazy loading boundary so introducing another chunk of the application at this place in the route hierarchy also to kind of keep the structure of this application and not change the code too much except for splitting it up into all these libraries it's another reason we're going to stick with this one this routing structure for now even though it does add to the size of this this chunk of the application but so i will commit this this is a refactor add list route so now when the final step i think is extracting these two services or sorry these two components here the crisis detail component and the crisis center home component so where do they belong let's look at the libraries we have do they belong in the feature shell no most definitely not do they belong in a feature list maybe it could be a nice starting point like we could have could just create another folder here or just paste them in right these two move them up here yeah that could be a good starting point um especially since there's no lazy loading boundary here and we're not looking to change that at least not right now so yeah i mean a detail component or feature is also kind of related to the list component or the list feature at least especially when they're shown at the same time and they are in this app we'll open it once we finish this refactoring what about the home component well doesn't really have much to do with the list but because the way this app is currently structured yeah let's let's do that let's take these two folders with components cut them out and add them to the feature list library and now we again get this problem of oh they don't have a module they don't have a scam so we have to create scams for them crisis center home module yes this is going to be an ng module the name of crisis center home module it's going to declare prices center home component uh it's not going to export it because it's a routed component but we're probably going to need some imports so let's go look at them template up this yeah that's a simple one so actually we don't need any imports nice so we need a scam for the crisis detail component that's called the crisis detail module prices detail module player exactly one component the crisis detail component that's a sad import ah much cleaner so does it need imports let's have a look at its template and there's something in here and the angular language service is certainly complaining can't bind to ng module it's not a known property of input so ng module which angular module would that be for using that directive right it's the forms module isn't it there we go and now the error message is gone there's nothing else well ngf that's kind of interesting because ngf to use that we need the common module but we don't have that in this scam right now maybe visual studio code is just confused somehow but i definitely need to add the current module now so that we can use ngf there we go another scam and okay just committing this something broken right now we're going to fix it very soon move crisis detail and home components to list feature okay okay so yeah final step of extracting things out from this page module here um crisis center routing module we have these two grand children routes or whatever the nesting level is at this point we want to take them and move them into their shell library shell module right here and now we need access to these components the detail component the home component and of course these other services right here i think that can the activate card is available from data access navigation oh that wasn't a pretty import for some reason oh now we need access to these two components so we have to export them from the feature list library export star from lib presses center home both need the module but also the component and organizing alphabetically here and another one is crisis detail slash component and slash module there we go now we can import them but to be able to route to them now we need to import them here so now we need to say isis center verify that import oh it got ugly man here and this one prices enter home module and crisis detail module but all from the feature list library inside the crisis center domain uh let's just enter retail module what was it called this is detailed but yeah now we import scams we can they are declared and we can route to them but it's also we're also in this situation again that we can see that they're not lazy loaded they're eagerly loaded as part of this shell library which means that this whole domain is currently in one big chunk but that's the way it already was in this application so we'll leave it this way for now but there's certainly room for improvement you're asking alexander if i have plans to have one data access library per domain or one for fee each feature live it depends right now uh we only have the crisis service for this domain and that's the reason i only created one data access but in real big applications uh you most certainly is are going to have or it makes sense often to have multiple data access libraries maybe you have two different web apis or websockets whatever um but you're only using it in this one domain so you should scope it to this domain until you reach the point where you will be sharing those web apis between multiple domains or multiple applications then we can heist them or raise them up to a shared grouping folder instead and yeah just move those data access libraries into there which is another point in favor of having these reasonably granular data access libraries for example one per web api but right now it's sweet and simple so we just need this one data access library but we do need that data access library because um this crisis service is reused between multiple features even though it seems that they're all ending up in this one list feature library now but that's something i would change i would lazy load them so i would take these detail and home and put them into separate features even though they're very simple in this tutorial application and in in real application they would be more detailed so they they would as almost certainly um warrant for a it would make sense to create a separate feature library for each of them in my opinion and my experience um but but yes certainly i another thing i i read from your question here is i put data services in data access libraries i don't put them in feature libraries i mean you can if it makes sense to you feel free to keep them inside the feature library to me they almost yeah it it makes sense to put them in data access libraries that way it's it's a really focused library it's easier to test in isolation because you know you certainly don't need any angular ui or anything like that to to test them they're even candidates for reuse across frameworks and things like that because they're not in the perfect world they're not angular specific but if we look into a service like this one it has this injectable provider right there's ways to get around this but a behavior subject for example is not inherently angular specific and think about something like akira which is also framework agnostic yeah enough about that um hello i'll try to pronounce your name sorry if i get it wrong gaurav in danish i don't know um where are you from um you're asking garaf does the ui lips oh can you also have a ui library per domain or per feature yes yes that um okay uh you're from india nice to meet you karaf so does it make sense to have let's say a single ui library per domain or per feature hmm it depends and there's no i mean the other things i said it's just my opinion it's based on my experience you can you can whatever makes sense to you just make sure to stay consistent in the workspace and agree with your team about this but regarding uh data acts or sorry ui and feature libraries okay so say we only had this crisis list component here and this feature list library this is a mixed component meaning it's both a container component or and a presentational component and because it's both it's neither so it's a mixed component it has presentational concerns and it also has um yeah like the glue between the data axis layer and the presentation layer that's a container component so it's a mixed component if say we split this into a crisis list container component and a crisis list presentational component would it then make sense to have um ui list library um which only contained that one presentational crisis list component if it makes sense to you you could do that or maybe if instead of just one container component and one presentation component say we had three container components and three presentation components now it could make more sense to have a ui library that fits with every component or most of the components inside of this feature library and the good thing about starting to extract presentational components into ui libraries is that at some point it turns out that um they are they they start to look alike like you start some patterns start to arise in some applications so that oh this is a i have a list component oh i could i could make that more abstract i could reuse it between multiple features or multiple domains multiple applications um i mean it's obvious with something like a component or another user controls a uh a country picker or something like that but even with something like a list component you might start to see once you extract all these presentational components you start to see similar patterns and we shouldn't generalize or make it abstract too early because it might be a coincidence that the components look similar but extracting the presentation components and even putting them in ui libraries allows us to start seeing those patterns and see oh does it make sense to make a more generic component out of this how many places do i have this duplicate code in and yeah so it can make sense do we need just one per feature or one per domain maybe maybe if it's um maybe if it's a very small domain we can start with just one feature library and one ui library or maybe we can just start with one feature library and put everything in there and usually that's what i start by doing i have just one feature library for i have a feature library for this list feature but i will i will split this mixed component into a container component and a presentational component but i will keep them both here in this library until the feature starts to grow then i might be thinking about whether i would put them in a ui library if i put them in a ui library another benefit is um i might start to get something like storybook starts to make more sense i mean i could do that in a feature library as well but yeah presentational components and classes are just different from the smart components and and routed components and the shield components and the page components so they really the presentation components belong in ui libraries but of course we shouldn't make the libraries to granular we shouldn't have usually we shouldn't have just one container component in here and one presentation component in in a ui list library yeah so it depends uh but certainly we can have one ui library for a domain and one for a feature that that can make sense in some circumstances or to start out and that's similar to how here we see that i'm starting out with just one domain library for this crisis center domain and one data access library for this crisis center domain because i have just one service with some fake data in it that's all it has and i have just one interface inside of here one domain entity inside of this domain so i don't have a reason to have multiple data access libraries multiple domain libraries right now inside of the crisis center but that could change um it could change i could also have called this one the domain dash crisis could have called this one data access dash crisis so that i wouldn't have to rename them once i the need for multiple libraries occurs um but then again i might be trying to come up with a clever name too early um and it's it's nice to start by having these junk libraries and then once you start putting things inside of them you realize oh these are not really related are they so maybe i should have two domain libraries so maybe i should have two data access libraries so it's a good starting point to have one data access for a library for domain one domain library and in some cases one feature library uh maybe it's the feature page library is a good starting point and in some cases maybe just one ui library yeah it's a good starting point for new domains or new applications and graph you have seen one per domain in the angular spotify repo yeah so that's a recent one i don't remember who created it but it's a spotify clone created with angular and you had you're saying there was one ui library for each domain yeah well it's certainly a very valid pattern to be using but at some point the feature grows and then you don't want to have just one ui junk library with things that are not really related other than the fact that they're used somewhere in the same big domain so good starting point but as the application or the domain or whatever you want to call it the page the feature as it grows one library will become too broad it needs to be more granular you need to have things that have cohesion that are related to each other so that when we make changes we affect the parts of the application that are actually affected not just because everything is importing from this one ui library inside everything in this domain is importing from that one ui library so that is works against nx tooling so it's not good for a big domain yeah uh you know i'm going to take just a five minute break so you forget to look at this back from the break thank you for hanging in there it's been two hours but let's see if we can finish and finally finish this um started by extracting the shell library from the this one junk page feature library we ended up extracting a data access library a domain library this list feature which actually has multiple components inside of here and of course the shell library itself so how close are we to finishing this thing okay there is one more issue oh i have uncommitted changes now um should i commit them now yeah i should move this child route shell good and now i can worry about this final one the crisis detail resolver service what on earth is that so it's probably here in the feature page library there it is crisis detail resolver service so it's a route resolver and it resolves a crisis so a route resolver works in the way that there will be route data available once this route is loaded so the crisis detail component and that route data there will be a property named crisis and it will have the value that is resolved through the service so the service has a resolve method it gets this activated route snapshot which has a parameter map with the id part which corresponds to this id in the route so the id of the crisis we want to look the details for um it then takes the cs it's probably crisis service yeah here it is get crisis so the crisis details for that id i'm going to take the first value of this observable and then if there's data so if it's a valid id basically we'll return the observable of that crisis if there's if this id is if there's no crisis with that id it will actually route back to the crisis center top level feature route and return and empty observable good so this crisis detail resolver service is related to this crisis detail component or specifically its route so it should be located in the same location as this crisis detail component so where is that well yeah where's that located let's go to the definition it's here so we need that same resolver service in this uh we need to move that up here through crisis detail and we can have it in that even though it's was a component and a module folder and now we have this service inside of here that is perfectly fine so but the thing is now we need to export that from this feature list library so here the crisis detail resolver service is now exported from this library and now we can start to see that how related are these things um i mean do i want to load all of this in a chunk i mean all of this is one chunk that's not very performance oriented um i mean it might be better to lazy load them on demand right and that's usually what i would do and maybe we'll do that and run some experiments um some other time for now now we have exported it which means that the shell module i'm able to import it but that was another refactoring commit move prices detail resolver to list feature okay let's see where we're at now crisis center um the module no red things no red squigglies this uh shell module no red script squigglies the shell component no reds quickly everything seems to be fine um so what do we have left in that original feature page library let's have a look so basically all of this crisis center home component is now gone crisis center component which is a shell component is now gone the detail and the list component is now gone so what is this module doing at this point uh it doesn't declare any components anymore so we can remove these ui modules rigid modules so at this point it's importing this crisis center routing module let's open that up and these are all the routes that we have just moved to our shell library and we have home route we have detail route we have list route as well and we have the crisis center component which is the shell component so at this point this routing module is doing exactly nothing and which means that this crisis center feature page module is doing absolutely nothing so this whole feature page module their live feature page library is now useless obsolete so let's remove the name of the project which is crisis center feature page and seems like it will even verify whether it's imported by someplace in our application which it isn't at this point so run now it's deleted and it's deleted from the configuration files nx json workspace.json ts config base json very nice let's see and it's gone sweet delete page feature library feature there we go all right exciting because now ah let's f one thing here let's let's look at this dependency graph again and let's look at let's focus on the crisis center feature shell which is what we have created in this episode so the two of heroes app is this is everything still set up right oh just a second managing too many screens right now okay so it's we're still running good okay so the two of heroes app is importing the crisis center feature shell which is a manfred styre shell library which is then importing data access navigation and the crisis center list feature if we focus on this one you get a cleaner look here we see that we have this shared library it's a ui library with dialogues which is also currently imported into the app um we see the crisis center domain library which is used both by this list feature but also by the data access library for the crisis sensor domain which is in turn depending on the shared messages data access library so basically everything up here is ui presentational of course also the ui library here and this is our domain layer and here is our data access layer and here we see it by grouping folders so this this is what we have been doing today we have structured the crisis center domain before it was just one page feature library and it turned out we didn't even have like well you could say that our i mean we could also have called have called it instead of a shell we could have called it a page because it contains basically the crisis center component which is the crisis center page but since just to make it clear that this is the we're using the shell pattern here the shield library pattern we call the feature shell instead and this should be a little more than a router outlet which is the case here maybe some shared i don't know menu navigation something like that but even that should probably be extracted to its own library ui or feature library so very little should be in here typically in in a shell component such as this one you might also call it a page component but now we have a shell library with a shell component and it's importing this list feature which if you remember has what is it like three components inside of it and it's using this data access it's using the domain and some other time let's do the same thing again but for these other three domains the heroes the admin and the auth domains that will be a fun exercise and another thing we could do is starting to optimize some things here for example lazy loading some of the components so that not everything will be in a single bundle which basically right now everything inside of this whole grouping folder even though it's divided into four libraries they will be in the same chunk is my guess based on yeah experience with angular and webpack so that was the dependency graph let's try now to start up the app see if everything's working come on angular now we can see here which chunks are here so we have a very tiny main file i mean these are development chunks they will be different in production but just 81 kilobytes of the main bundle that's pretty sweet and two lazy chunks the admin feature page and the crisis center feature shell so that was what i was assuming was the case that there's just one chunk with all the components and the data access services and and all of that in just one bundle i mean it's not big but this is only because it's not using something like angle material or other ui component libraries um it's it's only using very simple styles so this this might already be an issue in a real application with a more feature rich page with using a ui component library such as angular material okay let's look at the app zooming in there it is let's go to crisis center oh let's also open the console just to see here we go let's reload okay pre-loaded the crisis center because of this selective pre-loading strategy service but let's go to the crisis center and here's the the sky full of great white sharks um sky rains willabies uh welcome to crisis center so this is actually that crisis center home component and when we click a crisis it will be the crisis detail component another thing just to see here is the chunks let's reload disable the cache and yeah so this this oh well let's go to the let's reload the default route with this heroes you still see this crisis center feature shell chunk is loaded because of this pre-loading strategy that is activated pre-loaded the crisis center see the chunk here it's uh 45 kilobytes yeah but just one bundle when we click um the different components we don't see any other lazy loaded chunk being loaded so everything in one chunk that is because of yeah what we discussed these um imports they're not lazy loaded either one of the routes inside of the domain um that's something we could change and optimize so now we have this many projects inside of our workspace it's starting to look like something but remember this was just extracting all the domains the shared services and so on and trying to structure just one domain here the crisis center domain even to the point that i would probably put if this was a real application i would probably have the detail and the home um they would be in separate feature libraries yeah that's how i would usually do it one section of the page is one feature library one dialog is either in a ui library or in a separate feature library or something like that yeah okay let's push all of this so now you can take a look at the code yourself if you want to i will once again just put the repo here and come comments and this article by nacho vasquez about the three different libraries and shell library patterns and that's it it was a long one but it's also an a very advanced topic one that i recommend you read up on in that article by nacho and maybe try doing it to one of the other domains yourself and maybe i'll do it in another episode but there's i think there's three more domains right so you could you could do it uh try doing it yourself now you have an example of one of the domains so try one of the other domains and see if you can figure out how to do it feel free to ask me questions you can reach me on twitter or you can join our this is learning public discord server but you can also send me a tweet or a direct message on twitter or any other place you see me hanging around so that was it from nx after dark it is very dark now in denmark very dark and cold and it's actually a new week now we have past midnight and i have a long commute tomorrow so it's going to be a long day but it was fun hanging out and thank you all for hanging in there and thank you for the questions alexander garof corbin thank you for coming by and yeah i mean this is a long episode but lots of good topics to discuss great questions uh it's difficult to nail this shell library pattern but it's really useful and you can see that it forced us to think about our whole architecture from a structural standpoint okay you read the article before but it was difficult to understand yeah you kind of you need to i mean we did our best to provide both visuals and code and explanation but it became a 14-minute article because there are three parts and and conclusions and all that so and and also yeah i mean if you don't see why you would need it um it doesn't it probably doesn't make much sense but it's something that is also this pattern is described by narwhal in their angular mono repo book it's described by munford steyer in his domain-driven design and microfrontends and monorepo's book or whatever it's called these days it's a free ebook from manfred steyer and then this third composite shill library pattern to add some more support some more use cases is the one nacho and i uh made up for her for this article um yeah so now you've seen it in practice you can go look at the code uh it would be very fun to see you do the same thing for the other domains so fork the repo and try doing it on your own that will be very fun i probably won't do all three of the other ones the remaining ones uh anytime soon i mean i might do another one if i get time but probably not all of them i'll find something else to do in this repo like setting up the workspace lint rules or maybe some additional tooling or start adding tests or something fun like that so that's it for today i hope you learned a lot feel free to ask me questions and keep learning bye for now you
Info
Channel: Lars Gyrup Brink Nielsen
Views: 182
Rating: undefined out of 5
Keywords:
Id: eEfSlaCr6PQ
Channel Id: undefined
Length: 141min 11sec (8471 seconds)
Published: Sun Sep 19 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.