Our angular 4.3.6 application has lazy-loaded modules, such as Fleet, Maintenance, Car, etc.
My top-level app router looks like this:
const routes: Routes = [
{ path: '', redirectTo: 'fleet', pathMatch: 'full' },
{
path: '',
component: AppComponent,
canActivate: [AuthenticationGuard],
children: [
{
path: 'fleet',
loadChildren: "./modules/fleet.module",
canActivate: [AuthenticationGuard]
},
{
path: 'car/:id',
loadChildren: "./modules/car.module",
canActivate: [AuthenticationGuard]
},
{
path: 'maintenanceProgram',
loadChildren: "./modules/maintenanceProgram.module",
canActivate: [AuthenticationGuard]
}
}
We do have a shared module with generic components (we have lots of them) used throughout the application. There are, however, some components like modals which are shared only by the MaintenanceProgram and the Car modules, but not used anywhere else.
In an effort to keep the shared module reasonable, I include these once-reused components only in the MaintenanceProgram module, export them, and import the MaintenanceProgram module into the Car module to have access to the exported components.
Both the Car and MaintenanceProgram modules have the following embedded child routes invoked in their respective @NgModule.imports[]:
Car:
const CarModuleRoutes = RouterModule.forChild([
{
path: '',
component: CarComponent,
canActivate: [AuthenticationGuard]
},
{
path: ':id',
component: CarComponent,
canActivate: [AuthenticationGuard]
}
]);
and Maintenance Program:
const MaintenanceProgramModuleRoutes = RouterModule.forChild([
{
path: '',
component: MaintenanceProgramComponent,
canActivate: [AuthenticationGuard]
}
]);
This is obviously not the correct approach either
- to child routing, or
- to module transclusion
because when I load the Car route, I get the Maintenance Program's default route.
I have tried:
- Changing the order of the import of
MaintenanceProgramModuleRoutesandCarModuleRoutesinCarModule's@NgModule.imports[], - Removing the empty path from CarModule.
*Is the only solution to create another shared module that contains the shared components without a router, or is there another, more elegant way to do this?*
This is a reduced example, we actually have many routes and hundreds of components which are reused only twice or three times. This problem will surely persist into the future as the application grows, so I need a scalable and maintainable solution. Creating tens or more extra shared modules is just infeasible.
Actually, when creating a shared module, there is no need to care about modules which uses a little part of the shared module, because Angular's tree-shaking will keep only the used code from an imported module, and remove the rest.
I've prepared a minimal project to demonstrate it: https://github.com/youkouleley/Angular-treeshaking-demo
This project has two lazy modules:
AModuleandBModule. Both of these modules importSharedModule.SharedModuleexports three components:AComponentwhich is used inAModuleonlyBComponentwhich is used inBModuleonlyBothComponentwhich is used inAModuleandBModuleHere is what you'll get when
ng building this project in production mode and opening the4-es2015.<hash>.jsfile:Note that the
BComponentfrom theSharedModuleis missing from theAModulechunk. Sames goes forBModulechunk that excludesAComponent.Also, note that this behavior is obtained when setting
commonChunktofalsein the build options. This option allows you to choose between:false: Bundle the needed parts of theSharedModuledirectly into the lazy modules that imported it. Pro: Even loading time between lazy modules. Con: Some code fromSharedModuleis duplicated between lazy modules chunks, higher app size overalltrue(default): Have a common chunk that contains the parts of theSharedModulewhich are used at least by two lazy modules (the rest is bundled into the lazy modules themselves). Pro: No duplicated code, lower app size overall. Con: The first lazy module is slower to load (it loads the common chunk even if the current route doesn't need it)As a conclusion, Angular build provides optimizations for the
SharedModulewithcommonChunkset either totrueorfalse(depending on your context) you don't really have to worry about yourSharedModulesize. Thus, you don't have to try strange patterns like you did, with hybrid modules fulfilling the feature module role, and the shared module role at the same time.