简体   繁体   中英

How to achieve convention-over-configuration for Angular?

I find it somewhat inconvenient having to manually register my Angular MVC components and services within the root module (AppModule). It becomes even more inconvenient when working in a team. Ideally, developers should only add three files - a component, a view and a service without touching any other "infrastructure" files.

  1. I tried to not register my services in providers array, and the services still worked just fine. However, I'm not sure what would be the long-term consequences of not having them there. In which cases I would want my services in providers array?

  2. Then I tried to not register my components in declarations array and, of course, Angular failed with a message "Component BanksComponent is not part of any NgModule or the module". This seems to be a roadblock for the "convention-over-configuration" idea.

  3. It would be great to be able to add component-specific routes inside a component code file and somehow make Angular Router automatically collect those routes from all components that have routes defined (similarly to how ASP.NET MVC Route attribute on controllers works). Is there any solution for this?

Should I ditch the idea entirely and accept the fact that Angular just can't work that way?

You can put your Angular components in different modules. This has the benefit that you can better manage your dependencies and developers won't have to touch the same files.

A folder structure that I use in all of my projects:

core/
- login/
- auth/
- core.module.ts // Register the root routes here (RouterModule.forRoot)
- core.route.ts // Your lazy loaded routes for the core modules (login for example)

feature/
- home/
-- home.component.html
-- home.component.scss
-- home.component.ts
-- home.module.ts // Register the component and module route here (RouterModule.forChild)
- feature.module.ts // Register the feature routes here (RouterModule.forChild)
- feature.route.ts // Your lazy loaded routes for the feature modules (Example: The home page)

shared/ // Put any components/pipes/services that are shared over multiple components here
-- shared.module.ts // You can put dependencies that you share across multiple modules here (Example: Angular material imports)

app.module.ts
app.component.ts

This structure separates the logic for authentication, pages and shared functionality. It also bundles a component/small module so that it can be developed independently and can be replaced easily.


Example

You can find an example on how this fits in an actual application in this stackblitz .


To answer your questions

  1. Since Angular 6 you can register your services with the @Injectable({providedIn: root}) syntax. What this means is that your service will be globally available (you won't have to add it to the providers array before you can use it) and will be automatically removed from the prod bundle (via tree shaking) if it is not injected in any place.

  2. Components should always be registered in the declarations array. But you can make small modules where you declare the components.

  3. Via the RouterModule.forChild() you can create component specific routes. Combine this with lazy loading and you have a better overview over your features and better overall performance.


Lazy loading

You can improve the speed and decoupling of your application with lazy loaded routes. This is because the lazy routes ( loadChildren in the routes array) only point to a path. This way you can replace the module with an other module (that has the same name), without changing the reference (Even less files we need to change! :D).

Example import:

{
  path: HOME_MODULE_ROUTE,
  loadChildren: () => import('./home/home.module').then(m => m.HomeModule),
  // Add auth guard here to only show the page when the user is logged in
},

To further improve the performance of the application you can use a PreloadingStrategy . I would advice to use the PreloadAllModules strategy so your modules are loaded when it doesn't bother the user and it speeds up the the further loading and navigation of the application ( more here ).


Usage of constants over strings

In order to avoid a lot of debugging and/or runtime issues when you remove a route, I advise to use constants. This way you have 1 place where you define the page routes and can avoid string comparisons. Do note that you need a separate file for this. You cannot add the routes in the routing file, since that would create a circular dependency.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM