ChatGPT解决这个技术问题 Extra ChatGPT

Should I create a module per component in Angular 4+ app?

We have a medium sized Angular 4 application (+-150 components).

Many of these components require the injection of service classes and require the declaration of other components in the app.

An approach we have been experimenting with, and have found to be much more developer friendly, is to create a module per component. The module imports the child component modules and provides (or imports) all the services needed by the component. It also exports the component itself so that other components can reference it through the module.

It makes the composition of components a breeze and the setup of the test fixture of a component very simple (this is where there was previously a lot of repetition of dependencies and child component tree dependencies). This approach seems to match the component based architecture and allows for a form of encapsulation around what a components dependencies are. It feels just too good to be true ;)

My question is, what is the performance (or other) impact of having so many modules?

Thanks for your thoughts. This approach brought our test run times down massively. From 2mins30sec for 700 tests to 5 seconds. Much less developer overhead ;-) Hmmm... not sure why my Question has been downvoted. Maybe it is a sign that others think it is a bad idea.
I actually think that is the way to do it, one module includes parent and child component, remember when angular was beta we could´t do this... and we had one module for huge apps, that was the opposite of friendly, not what Mark says
If you're developing a library, having a module per component is often the way to go. Check ng-bootstrap for example. If you're developing an app, it's better to group components by feature. not sure why my Question has been downvoted. - don't pay attention, this is the illness of SO
@Bob, a consumer of your library may choose to use only one component from your library and so it'd be convenient to import that component module instead of the entire lib module with multiple components.
@MarkWhitfeld, yes, they are all compiled and merged. you can watch my talk at ngconf or read my article on modules. ask questions if any :)

L
Lucas Basquerotto

I consider one module per component the best way to design your Angular apps.

If it depends on other components, you can include only the component modules related to each component that is a direct dependency and don't need to care about indirect dependencies.

It may seem more work at first, but it will pay you back will less maintenace problems.

If ComponentA depends on ComponentB that depends on ComponentC create a:

ModuleC related to ComponentC

ModuleB related to ComponentB that imports ModuleC

ModuleA related to ComponentA that imports ModuleB (it doesn't need to import directly ModuleC)

If ComponentB now depends on ComponentD (like including <my-component-d> in the template) and stops depending on ComponentC you just change ModuleB and all components that depend on ComponentB will work fine, if you are using this approach.

Think now about hundreds of components. How many components will depend on ComponentB?

I consider this problem similar with the old way (or not too old) of including js files in script tags:

<script src="build/a.js"></script>
<script src="build/b.js"></script>
<script src="build/c.js"></script>

And if you change b to stop depending on c and starts depending on d, all pages that import b have now to import d, and so on, leading to a maintenance nightmare. You may also forget to remove (the now unneeded) c.js and import it needlessly in some pages, increasing your boot time (or worse, you remove it from all files that import b.js, but some page imports e.js that depends on c.js and you break some functionality of that page).

Instead I consider it much better to import:

<script src="build/bundle.js"></script>

or

<script src="build/vendor.js"></script>
<script src="build/main.js"></script>

and the dependencies are handled by a module bundler, like webpack.

There is the approach of making a module with lots of components and just import it, but you end up importing several components that you don't use and if you use lazy loading, your modules may become huge, unless you import that module in AppModule, making your boot time increase.

You can still use the approach of one component per module with feature modules. Just import the component module into the feature module (instead of the component itself):

feature.module.ts:

imports: [
    ComponentAModule,
    ComponentBModule,
    ComponentCModule,
]

(You may want to export them too).

I also consider this approach the best way when creating libraries, otherwise you would force the consumers of the library to import all the components, even if they only use 1 or 2 components in the library.

I'm experiencing this issue with ionic3: the minified ionic-angular library has 437KB of which 292KB are the components (hopefully it will change with ionic4). I use just a few ionic components, there was no need to import all of them, but I have no choice (unless I fork the repo or stop using it).

I have an app with 176 components and this was the best approach in my opinion. Before, I included several components in a feature module and it gave me some headaches later on. Also, it was harder when changing a component from a feature module to another (What about its dependencies? They were all mixed together).

I haven't found a satisfactory approach with services (@Injectable()) tough.

In the end it's up to you the decision. This is my opinion based on my experience.


Thanks for your answer Lucas. Although this question is hugely subject to people's opinions around the structuring of their app given their context I do believe that this is a really good way to go. Having taken this approach in my app I have experienced all the benefits you mentioned. The small amount of work in creating a module per component definitely improves the maintainability and compose-ability of the app. Apparently the module construct disappears through compilation so it doesn't even add an overhead. Thank you for your answer.
@MarkWhitfeld Yes! In my case the biggest problem was the initial change from the monolitic modules with several components to one module per component, but now I only need to create new modules when I create new components, and the time it takes for creating the module is surely much less than it takes to create the component itself (with the logic and the template), so I see the module creation as part of the component creation, and now it's much easier to change dependencies among components and removed unused ones.
Would you use one module per @Pipe ?
@LucasBasquerotto, Thank you for your answer. My Angular 7.x app uses lady loading and had a SharedModule containing shared components used across lazy loaded modules. I have refactored the app and I have now one module per component for the shared components. Before and after the refactor I ran npm run aot: the total size of chunks has decreased by 7.6%. So thank you for your advises :-)
@Yanal-YvesFargialla Cool! But the main reason is not even about the final bundle size, but the size that is loaded in the initial load (that affects the performance of the app at the startup). The less you have to load at the startup, the better. The ideal scenario is to only load what is really needed at the startup (although other modules could be loaded asynchronously, such as to not affect the initial load, but make lazy loaded modules start faster).