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