angular-architects / module-federation-plugin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dynamic loading of native remote module throws NG0203: inject() must be called from an injection...

ips219 opened this issue · comments

Hi...

I am migrating from webpack module federation to the new native federation, and I'm having some issues for loading dynamically the remote modules. In my application, remote modules are loaded dynamically, so I don't have an static manifest with the remotes that should be loaded.

In the main.ts I am initializing the federation framework without parameters. In this application, modules are dynamically loaded based on the user grants and requested on demand when the user enters in different sections, so at this point I don't need to initialize any remote...(I think this is the correct way)
initFederation() .catch(err => console.error(err)) .then(_ => import('./bootstrap')) .catch(err => console.error(err));
As I can see the shell remoteEntry.json is called to initialize the federation framework, so I think it is the expected behaviour
image

Next when the user enters a section which requires a module to be loaded, I call loadRemoteModule specifying as remoteEntry the remote module URL. The code is almost the same as in webpack module federation but chaging the parameters used, that are slightly different from webpack.
`

public loadFederatedApp(organizationKey: string, configName: string, appName: string): Observable<any> {
    const config = this.injector.get(ConfigurationService);
    const tenantId = config.getUserSettings().tenantSettings.tenant;
    const basePath = this.apiHelper.assetConfigService.configuration.basePath;

    let cmpPath = `${basePath}/staticResource/${tenantId}/${organizationKey}/${configName}/${appName}/remoteEntry.json`;
    if (environment.mfeComponents.hasOwnProperty(appName) && environment.mfeComponents[appName]) {
        cmpPath = `./${appName}/remoteEntry.json`; //dev only loaded from angular proxy
    }

    const loadRemotePromise = loadRemoteModule({ remoteEntry: cmpPath, remoteName: appName, exposedModule: appName });
    return defer(() => from(loadRemotePromise));
}

`
This triggers some additional API calls to fetch some locale files and as I can see, the mfe remoteEntry.json is called to initialize the remote module. At this point I don't observe anything strange... Ithink it is correct.
image

My problem raises in the last step when I try to update the router configuration with the new child routes. In my current application that runs with Angular 17 and webpack based module federation, this code works fine:
`

this.router
.config.find(route => route.path == "shell")
.children.push({
path: apps/:orgId/${configName}/${appName},
loadChildren: () => {
return mfeAppModule //This is the emod from the loadRemoteModule
}
});
this.router.resetConfig(this.router.config);

`
Basically I take the emod from the angular module and push a new route to the router configuration, reseting the configuration of the router. After this I navigate to the application default route and it works fine with Angular 17 and Webpack Module Federation.

The new code based on native federation, throws this error: NG0203: inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with runInInjectionContext
image

Any idea of what can be the problem?

Thanks and best regards.

@ips219 I have same issue and noticed this happens when remote's Angular version is higher than shell's Angular version, maybe check this on your side as well? This doesn't happen with module federation as you said, only with native federation so maybe there is a bug with the version matching configuration (strictVersion: true, requiredVersion: 'auto') ?

Edit: I solved this issue by making sure both remote and shell have same versions (I think it checks for angular/core). I compared http://localhost:4200/remoteEntry.json and http://localhost:4201/remoteEntry.json and verified they have same versions. Still, I think this is a bug, unless it is not officially supported in native federation

Hello @ZissisT ...

You were right, it seems that between the ng upgrade of my shell and my mfe there was a new published version in npm and both versions were not aligned, I didn't noticed because my current version with module federation was working fine...

After aligning both of them native federation is working fine.

Thanks for your support!

@ips219 this should not be set as completed in my opinion. This error should not happen when requiredVersion is set to false in manifest config. In module federation if requiredVersion is set to auto, an elegant error message is thrown saying that version dependency is not met etc. If requiredVersion is set to false, no error is displayed. Same thing should happen in this case but it doesn't.

@ZissisT Understood.... I will reopen the issue to let project owners decide.

Best regards...