Description
This is a feature request.
I'd like to start discussion around @ngtools/webpack
supporting code splitting by third party libs (including ui-router-ng2
).
Currently the code splitting support in @ngtools/webpack
has a soft dependency on @angular/router
.
My understanding is that:
@ngtools/webpack
loader invokes__NGTOOLS_PRIVATE_API_2.listLazyRoutes()
listLazyRoutes
finds lazy routes:- References the DI token
ROUTES
found in@angular/router
- statically analyzes the application.
- checks each
NgModule
for providedROUTES
- Checks each route for
loadChildren
and adds to the list of lazy routes. - returns lazy routes
- References the DI token
- processes lazy routes, redirecting imports to
.ngfactory.ts
and doing webpack magic
Goal
I think the goal should be to eliminate the dependency on @angular/router
and provide a router agnostic mechanism for third parties to supply code splitting information.
Today, UI-Router supports code splitting using @ngtools/webpack
by importing the ROUTES
token from @angular/router
, then providing the ui-router states as that DI token, i.e., { provide: ROUTES, useValue: module.states, multi: true }
. However, this forces ui-router to have a dependency on @angular/router
. It also forces ui-router to emulate the structure of @angular/router
by adding a loadChildren
property.
Proposal 1
Make the DI token configurable by @ngtools/webpack
.
Do not reference the token from @angular/router
in ngtools-impl.ts
, but pass the token in. UI-Router users could configure this somehow to use the STATES
token, for example.
This proposal is rather limited in its usefulness. Only one library could support lazy loading + code splitting in a given app.
Proposal 2
Move and/or rename the DI token out of @angular/router
Perhaps the DI token could be moved to @angular/compiler-cli
, @angular/common
, or @angular/core
. This eliminates the need to depend on @angular/router
. Additionally, move the token to its own ES6 module. Today, importing the ROUTES
token from @angular/router
brings in unrelated symbols from @angular/router
into the ui-router bundle even using rollup.
This proposal still conceptually ties lazy loading to the @angular/router
. All terminology and code analysis assumes that lazy loading code processes @angular/router
routes. Third parties have to emulate the router's structure.
Proposal 3
Introduce a routing-agnostic token such as ANALYZE_FOR_LAZY_LOAD
.
Either @angular/router
or third parties should provide lazy load and code splitting information using this token. I propose instead of providing an array of specifically structured objects such as ROUTES
or STATES
, that only the lazy load information need be provided, i.e.:
{
provide: ANALYZE_FOR_LAZY_LOAD,
useValue: [
'./child1/child1.module#Child1Module',
'./child2/child2.module#Child2Module'
]
}
The @angular/router
would then provide the module's lazy load information by doing something like:
const lazyRoutes = ROUTES.map(x => x.loadChildren).filter(identity);
const provider = { provide: ANALYZE_FOR_LAZY_LOAD, useValue: lazyRoutes, multi: true };
The knowledge about the lazy load declaration object (i.e., what the loadChildren
property means on a route) is moved from @angular/compiler-cli
to the library that owns that structure (i.e., the @angular/router
).
Of these three proposals, this one is my favorite as it separates concerns nicely and provides a clear mechanism for lib authors to use.