TL;DR
How can I have a conditional route with conditional import of the corresponding Angular library during build time, depending on a feature flag in the environment file?
Background
I'm having a route configuration that lazy loads an Angular library / module:
{
path: 'wishlist-management',
loadChildren: () => import('@mycompany/thelibrary').then(m => m.TheLibrary),
canActivate: [AuthGuardService],
canLoad: [AuthGuardService],
}
The requirement is, that it should only load the library, if it is enabled with a feature flag in the environments file. For that, I've implemented an AuthGuardService with the canLoad method:
public canLoad(
route: Route,
segments: UrlSegment[],
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.isFeatureEnabled(this.router.getCurrentNavigation().extractedUrl.toString());
}
This canLoad method is also provided in above mentioned route configuration.
However, supposing the feature flag is false and therefore canLoad returns false, and that therefore also @mycompany/thelibrary is not installed as npm dependency in the project, I'm getting an error:
Error: Module not found: Error: Can't resolve '@mycompany/thelibrary' in '/home/user/projects/myproject/frontend/app/node_modules/@mycompany/someotherlibrary/fesm2020'
which is as expected, since canLoad will only load the chunk file at runtime, but is already building it during build time.
However, how can I achieve a fully conditional route and import of the corresponding library / module already in build time, only if the corresponding feature flag is true? It should only try to import the library if the feature flag is true.
I have found a blog post solving this problem by passing null in the route configuration and then manipulating the loadChildren dynamically on router event hooks. But this feels hacky and not the way to go for me.
You have to completely remove any reference to your library from code before build. Use
fileReplacementsconfiguration inangular.jsonfile. We will replace this file with a dummy based on the build environment.Create a separate file for loading the route.
src/environments/thelibrary-routes.ts.Then in your routes load it as
Then create a second dummy file.
src/environments/thelibrary-routes.empty.tsNow this is the cool part. Edit your angular.json file and under
build.configurationsadd a new one for when your module should be excluded (or if it fits your case, do it in theproductionconfiguration, if you want to exclude your module in production for example). Under your desired configuration, add a new entry tofileReplacementslist like this:angular.json:Note that the first entry in
fileReplacementsis already there. Only add the second one.You can use this approach to include/exclude routes depending on your build configuration. Optionally you can set the routes inside the
environment.tsfile itself if you don't want to create a new file for the routes, in which case you wouldn't need to editangular.jsonfile.