Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nx angular dynamic mfe got NG0203 error #2797

Closed
5 tasks done
mehrabix opened this issue Jul 25, 2024 · 6 comments
Closed
5 tasks done

Nx angular dynamic mfe got NG0203 error #2797

mehrabix opened this issue Jul 25, 2024 · 6 comments

Comments

@mehrabix
Copy link

mehrabix commented Jul 25, 2024

Describe the bug

I had no issuse since i used nx mfe with angular 15,
but i tried to migrate to angular 18 and got this error when navigating from shell (host) app to another mfe
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. Find more at https://angular.dev/errors/NG0203
i also saw this topic
nrwl/nx#19121
and then i tried it on my two envirements which is a windows system and debian linux, and in both cases got the same error.

Reproduction

clone this repo
https://github.com/mehrabix/nx-angular-mfe

do npm i

run this command:
npx nx serve shell --devRemotes="first-microfront,second-microfront"

Used Package Manager

npm

System Info

System:
    OS: Linux 6.1 Debian GNU/Linux 12 (bookworm) 12 (bookworm)
    CPU: (4) x64 Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz
    Memory: 2.24 GB / 7.53 GB
    Container: Yes
    Shell: 5.9 - /usr/bin/zsh
  Binaries:
    Node: 22.5.1 - /home/linuxbrew/.linuxbrew/bin/node
    npm: 10.8.2 - /home/linuxbrew/.linuxbrew/bin/npm
    pnpm: 9.5.0 - /home/linuxbrew/.linuxbrew/bin/pnpm
  Browsers:
    Chrome: 126.0.6478.114

Validations

@mehrabix
Copy link
Author

mehrabix commented Jul 26, 2024

Hi,

I got some clues. Clone this repository (it's mentioned in the Angular MFE tutorial: https://nx.dev/recipes/angular/dynamic-module-federation-with-angular):

https://github.com/Coly010/nx-ng-dyn-fed

Run:
npx nx serve employee --devRemotes="dashboard,todo,login"
navigate between remote links
The Angular version is 18.0.4, and it works perfectly.
Then, run this in order to migrate to Angular 18.1.2. It will migrate successfully:
nx migrate latest

After that, run:
npx nx serve employee --devRemotes="dashboard,todo,login"
again.
navigate between remote links
It will not work anymore, and you will get the NG0203 error.

@Coly010
Copy link
Contributor

Coly010 commented Jul 26, 2024

@mehrabix

Can you open this issue on the Nx Repo? It’s not directly related to this package.

@mehrabix
Copy link
Author

mehrabix commented Jul 26, 2024

Hi @Coly010
I don't think it's related to Nx.
as i mentioned it's working on Angular 18.0.4 and not 18.1.2
Anyway
i did it. Thanks
nrwl/nx#27162

@bh3605
Copy link

bh3605 commented Aug 2, 2024

@Coly010 This bug most certainly is not related to Nx. I'm doing the same thing with an Angular 17 remote and receiving the same error. In my case, however, my host is a single spa MFE using systemjs externals, @angular-architects/module-federation to load this remote, and I'm trying to use this example to point the angular dependencies to the systemjs map. Now, before I tried figuring out this remote plugin stuff, I noticed the remoteEntry file can't even figure out how to share the angular dependencies so I've been trying to reverse engineer the cause of this and haven't found anything yet. This enhanced mod fed plugin is missing something the webpack version isn't.

extra-webpackconfig.js

const modfedOptions = {
    library: { type: "module" },
    filename: "remoteEntry.js",
    name: 'CarrierPigeonApp',
    exposes: {
        './Component': './src/app/app.component.ts', // this is a standalone component
    },
    shared: //{ ...deps },
    share({
        // '@angular/core': {
        //     singleton: true,
        //     strictVersion: true,
        //     requiredVersion: 'auto',
        //   }
        ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
    }),
    // runtimePlugins: [require.resolve('./npm-runtime-global-plugin')],
    dts: false,
    disableManifest: true
};

module.exports = (config, options) => {
//   const singleSpaWebpackConfig = singleSpaAngularWebpack(config, options);

    config.experiments = {
        outputModule: true
    };
    config.output = {
      ...config.output,
      uniqueName: "CarrierPigeonApp",
      // depending on what imports the remote entry determines if this succeeds or not
      publicPath: "auto",
    };
    config.optimization = {
        ...config.optimization,
        runtimeChunk: false
    };
    config.plugins = [
        ...config.plugins,
        new ModuleFederationPlugin(modfedOptions)
    ];

  return config;
};

angular.json

"build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "outputPath": "dist/carrier-pigeon-app",
            "index": "src/index.html",
            "polyfills": [
              "zone.js"
            ],
            "tsConfig": "tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "scripts": [],
            "main": "src/main.ts",
            "customWebpackConfig": {
              "path": "extra-webpack.config.js",
              "libraryName": "CarrierPigeonApp",
              "libraryTarget": "umd"
            }
          },
          "configurations": {
            "production": {
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "500kb",
                  "maximumError": "1mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "2kb",
                  "maximumError": "4kb"
                }
              ],
              "outputHashing": "none"
            },
            "development": {
              "optimization": false,
              "extractLicenses": false,
              "sourceMap": true,
              "outputHashing": "none"
            }
          },
          "defaultConfiguration": "production"
     }

main.ts

import('./bootstrap')
	.catch(err => console.error(err));

bootstrap.ts

import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));

package.json dependencies
image

The shared resource map compiled using the enhanced mod fed plugin
image

The shared resource map compiled using webpack's mod fed plugin
image

As you can see, swapping out mod fed plugins leads to different shared mappings which is probably a separate bug altogether, but should give a hint that this plugin has a problem with Angular projects.

To be clear though, I receive the same error with both the enhanced mod fed plugin and webpack's mod fed plugin. My hope in figuring out the runtime plugin will lead to my remote to being able to access the same service instances my single spa mfe host uses.

@bh3605
Copy link

bh3605 commented Aug 2, 2024

Figured out my problem was using angular-architects' shareAll function. For some reason I needed to specify my shared dependencies the manual way and everything just worked afterwards

@ScriptedAlchemy
Copy link
Member

Angular Architects might be incorrect for V2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants