Home > Software design >  Angular cannot find shared component in NX
Angular cannot find shared component in NX

Time:12-08

I am trying to start a small microfrontend project in angular 15 with Nx (integrated) and module federation. At the moment I have two applications:

  • shell
  • video

I need to create package of shared components that will eventually be used as I add more apps. I created a shared/ui package in packages (with nx cli commands) and generated a widget component there that I need to use within the video app. However, when I try to use it I get the following error:

error NG8001: 'my-org-widget' is not a known element:
1. If 'my-org-widget' is an Angular component, then verify that it is part of this module.
2. If 'my-org-widget' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

My nx.json:

{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "npmScope": "my-org",
  "tasksRunnerOptions": {
    "default": {
      "runner": "@nrwl/nx-cloud",
      "options": {
        "cacheableOperations": ["build", "lint", "test", "e2e"],
        "accessToken": "x"
      }
    }
  },
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"]
    },
    "test": {
      "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"]
    },
    "e2e": {
      "inputs": ["default", "^production"]
    },
    "lint": {
      "inputs": ["default", "{workspaceRoot}/.eslintrc.json"]
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": [
      "default",
      "!{projectRoot}/**/?(*.) (spec|test).[jt]s?(x)?(.snap)",
      "!{projectRoot}/tsconfig.spec.json",
      "!{projectRoot}/jest.config.[jt]s",
      "!{projectRoot}/.eslintrc.json"
    ],
    "sharedGlobals": []
  },
  "workspaceLayout": {
    "appsDir": "packages",
    "libsDir": "packages"
  },
  "generators": {
    "@nrwl/angular:application": {
      "style": "scss",
      "linter": "eslint",
      "unitTestRunner": "jest",
      "e2eTestRunner": "cypress"
    },
    "@nrwl/angular:library": {
      "linter": "eslint",
      "unitTestRunner": "jest"
    },
    "@nrwl/angular:component": {
      "style": "scss"
    }
  },
  "defaultProject": "shell"
}

My `packages/shared/ui/src/lib/shared-ui.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WidgetComponent } from './widget/widget.component';

@NgModule({
  imports: [CommonModule],
  declarations: [WidgetComponent],
  exports: [WidgetComponent],
})
export class SharedUiModule {}

And this is the packages/video/src/app/app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { SharedUiModule } from '@my-org/shared/ui';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    SharedUiModule,
    RouterModule.forRoot(
      [
        {
          path: '',
          loadChildren: () =>
            import('./remote-entry/entry.module').then(
              (m) => m.RemoteEntryModule
            ),
        },
      ],
      { initialNavigation: 'enabledBlocking' }
    ),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

To be fair, I am pretty new to both Nx and microfrontends, so any help will do.

Any ideas?

P.S. Complete current code can be found here: https://github.com/mmvcode/mfa

Thanks.

CodePudding user response:

Since WidgetComponent is standalone component, you will have to import it instead of declaring it in SharedUiModule [Refer: https://angular.io/guide/standalone-components#the-standalone-flag-and-component-imports ]

Change: declarations: [WidgetComponent], to

@NgModule({


imports: [CommonModule, WidgetComponent],
  declarations: [],
  exports: [WidgetComponent],
})

And update entry.module.ts to import SharedUiModule as you have declared VideoDisplayComponent as part of this module (which internally uses your widget component)

import { SharedUiModule } from '@my-org/shared/ui';
@NgModule({
  declarations: [
    RemoteEntryComponent,
    NxWelcomeComponent,
    VideoDisplayComponent,
  ],
  imports: [CommonModule,SharedUiModule , RouterModule.forChild(remoteRoutes)],
  providers: [],
})
export class RemoteEntryModule {}

This should at least successfully build your application

  • Related