Angular 9 - Dynamic Lazy Loading Module - The request of a dependency is an expression

Viewed 1028

I would leverage Angular Lazy-loading feature modules to fulfill a pluggable frontend.
So the concept is create extension-points in my app where I can do something like this:

import('./customers/customers.component').then(lazyMod => {
   here use lazyMod.CustomersComponent to plug other component's template
})

I've developed the idea in a simple PoC in stackblitz:
https://angular-9-dynamic-lazy-test.stackblitz.io

Case 1 - OK - Pressing button1 of the PoC, it runs the following code and it's OK:

const { HelloComponent } = await import('./hello.component')

Case 2 - OK - Pressing button1(bis) of PoC, it runs the following code and it's OK:

const helloLazyModulePath = './hello.component'; //component already loaded in case 1
const { HelloComponent } = await import(helloLazyModulePath );

Case 3 - KO - Pressing button2 of the PoC, it runs the following code and I get error:

const goodbyeLazyModulePath = './goodbye.component';
const { GoodbyeComponent } = await import(goodbyeLazyModulePath);  

The error is: Uncaught (in promise): Error: Cannot find module.
A build warning says: Critical dependency: the request of a dependency is an expression

The reason should be this:
According to https://angular.io/guide/deployment#lazy-loading

The CLI runs the Angular Ahead-of-Time Webpack Plugin which automatically recognizes
lazy-loaded NgModules and creates separate bundles for them

It means that webpack angular tool, during the build phase, scans the source-code to find out @import('path') and to create a separated bundle for lazy-module.
So if the @import is dinamically used @import(variable), there isn't way for webpack to figure out which feature module must be built in a separated bundle.

I need to use @import(variable) because I know which plugin-module to import only during build phase, according to many factors, for example in which environment I'm going to deploy.

Is there a way (a workaround or a compile setup) to use @import(variable) without getting error at runtime due to missing separated bundle?


EDIT: In addition to the stackblitz , I pushed the same PoC in this github repo

1 Answers

How dynamic can the path be? I mean you should be able to know all the possible paths. So you can just do something like:

let componentToUse: Component;

switch (dynamicArg) {
  case 'a': 
    componentToUse = (await import('path/to/a')).ComponentA;
    break;
  ...
}

Related