๐ฏ Introduction
A page (or view) module is a module that represents a page or a view of an application. It is a collection of related components, directives, pipes, and services, routes and other page modules (sub-pages) that work together to form a cohesive user interface.
Page modules serve the purpose of organizing and encapsulating a page's functionality. They are the first component rendered after a user lands on a specific route defined in our app routing module, simplifying the management and maintenance of the page.
@Injectable()
export class PreloadModulesStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>){
if (route.data && route.data.preload) {
return load();
}
return of(null);
}
}
I almost always use lazy loading for my entry page modules, which results in a smaller entry file bundle and faster loading times. Additionally, I recommend a custom preload module strategy, allowing me to specify which pages I want to fetch over the network when app is initially loaded (so they will be fetched even if user didn't land on the specific route). This ensures that the modules are loaded quicker when accessed by the user later.
Quick example in my little app shows how JS chunks for Home and Movie pages are loaded and ready to use when application is loaded, while Settings page JS chunk is loaded after user has navigated to it.
๐ฏ Page Module Content
Page module also contains collection of components, services (http services, resolvers, guards, etc..) and all of the other Angular building blocks specific for that page that goes under the same starting route.
It also contains routing (sub-routes) definitions relative to page module path defined in app-routing.module.ts which means it will also contain other Page modules.
We are currently grappling with an ongoing issue of determining the most suitable level of nesting for our subpages. While it may seem intuitive to arrange our folders based on our routing definitions, I can attest that this can quickly become unwieldy and result in excessively nested files, which can be frustrating to navigate and runs counter to our primary goal of simplifying the folder structure.
So, my proposition is that we put all of the subpages into a single folder labeled "modules". Additionally, it is my recommendation that we place all components intended for use in the page module and its sub-modules in a folder titled "components", even if they are only utilized within a specific subpage.
๐ฏ Example
I will use this awesome page TheMovieDB as a reference for my example of setting up folder structure and routing:
I hope that folder structure is self-explanatory.
- shell (contain all of the components used for _hosting page sub modules that may share some repeatable layout like menus)_
- modules (contain all of the modules referenced in movie.module.ts in this case)
- components (contain all of the components used across any module - shared or not)
- services (contain all of the movie services)
- ... etc
The main objective is to ensure effortless access and customization of our codebase by simplifying the directory hierarchy and keeping it flatten as possible.
Top comments (6)
Thank you for sharing this experience and knowledge.
I'm struggling with a similar size project. Building modules / splitting my code into them for the first time and I'm having a hard time deciding what comes where, even though I'm reading and am chat-gpt-ing since 2 days about this topic. F.e. what about pages that right now are quite dumb components, and they don't need to be modules by themselves for now. should I still make them modules ? would I keep these dummer page components as components in a separate space ? where ?
I would love to see the full directory structure. Right now I'm jumping in your blog posts back and forth.
Hi @sebastian_wojtowicz_0238d
not sure if something like this can help.
github.com/dinodujmovic/fe-magic/t...
If you have your project on GitHub I can take a look
ah one thing I didn't understand.
If I use resolvers that are meant to load the needed data first, before routing to the next page, what do you do in the meantime ? like is the site hanging then ?
I route and then work with grey skeleton boxes while the needed object is not loaded yet (e.g. !(apartment$ | async) or similar and then instead of rendering an image or content I render a w:100%, h:100% big grey skeleton that has some sort of shimmer animation.
is that approach compatible with resolvers in some way ?
Yes. With resolvers your page (component) will render only after the API data has been resolved.
They are not a must - just if you prefer them for some specific scenarios.
Which will give an effect of application hanging - if you don't add some kind of indicator (like global - spinner, progress bar loader or whatever) ideally controlled by some global state service (example: loaderService.show(), loaderService.hide()).
Wow, that really helped a lot.
I already figured out and have digested all of the knowledge, but it's hard to apply and think all the new patterns at once (tried to apply all of them :D), and now your example repo came in the perfect moment, I could supplement and built on top of what I had already, confirm, see more, and just did minor adjustments to what I had so far.
My Code is private right now, though I would have no problems having you look. anyhow for now it's based on your post :D
any more links I should digest ?
hello @digitaldino
Thanks for sharing these experience about how you organize your module. is there any repository updated (the one you shared seem to miss many files in the codebase uploaded) with all the code or with just one page complete. I wanted to know if for example the movie-cast module is an Angular complete module or how it is oragnized.