I've been trying to create a POC project to work with the Native Federation in a NX Monorepo, following a DDD approach structure.
The mfe1 application in the project has a dependency to its domain and feature-content existing in the repo and defined in the tsconfig.base.json.
{
"compileOnSave": false,
"compilerOptions": {
"rootDir": ".",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "ES2022",
"module": "esnext",
"lib": ["ES2022", "dom"],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"@native-federation/mfe1/domain": ["libs/mfe1/domain/src/index.ts"],
"@native-federation/mfe1/feature-content": ["libs/mfe1/feature-content/src/index.ts"]
}
},
"exclude": ["node_modules", "tmp"]
}
I use the component defined in the feature-content in app.component.ts of the mfe1
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ContentComponent } from '@native-federation/mfe1/feature-content';
@Component({
standalone: true,
imports: [RouterModule, ContentComponent],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
})
export class AppComponent {}
That just show some random content via the tag <mfe1-content />
in the app.component.html.
But when I make changes to files defined in the mfe1 feature-content the build seems to be run but it looks like the changes are not detected and the live reload is not triggered. I have to refresh the page manually to see the changes have effect.
I'm not sure if i'm doing something wrong but when I run the application without the Native Federation build process everything works as expected.
I've created a github repo of this project to try this out.
Repro steps
npm i
npx nx run mfe1:serve
libs/mfe1/feature-content/src/lib/content.component.html
The live reload is not triggered, but it will if something is not buildable.
On the other hand npx nx run mfe1:serve-original --configuration=development
take changes as expected.
Additional infos
package.json
{
"name": "@native-federation/source",
"version": "0.0.0",
"license": "MIT",
"scripts": {},
"private": true,
"dependencies": {
"@angular-architects/native-federation": "^17.1.7",
"@angular/animations": "17.3.3",
"@angular/common": "17.3.3",
"@angular/compiler": "17.3.3",
"@angular/core": "17.3.3",
"@angular/forms": "17.3.3",
"@angular/platform-browser": "17.3.3",
"@angular/platform-browser-dynamic": "17.3.3",
"@angular/router": "17.3.3",
"@ngrx/signals": "^17.1.1",
"es-module-shims": "^1.9.0",
"rxjs": "7.8.1",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "17.3.3",
"@angular-devkit/core": "17.3.3",
"@angular-devkit/schematics": "17.3.3",
"@angular-eslint/eslint-plugin": "17.3.0",
"@angular-eslint/eslint-plugin-template": "17.3.0",
"@angular-eslint/template-parser": "17.3.0",
"@angular/cli": "~17.3.0",
"@angular/compiler-cli": "17.3.3",
"@angular/language-service": "17.3.3",
"@nx/angular": "18.2.3",
"@nx/eslint": "18.2.3",
"@nx/eslint-plugin": "18.2.3",
"@nx/jest": "18.2.3",
"@nx/js": "18.2.3",
"@nx/workspace": "18.2.3",
"@schematics/angular": "17.3.3",
"@swc-node/register": "1.8.0",
"@swc/core": "1.3.101",
"@swc/helpers": "0.5.3",
"@types/jest": "29.4.4",
"@types/node": "^18.16.9",
"@typescript-eslint/eslint-plugin": "7.3.0",
"@typescript-eslint/parser": "7.3.0",
"autoprefixer": "^10.4.0",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"jest": "29.5.0",
"jest-environment-jsdom": "29.5.0",
"jest-preset-angular": "14.0.3",
"jsonc-eslint-parser": "^2.1.0",
"ng-packagr": "17.3.0",
"nx": "18.2.3",
"postcss": "^8.4.21",
"postcss-url": "10.1.3",
"prettier": "2.8.3",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
"typescript": "5.4.4"
}
}
mfe1 project.json
{
"name": "mfe1",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"prefix": "app",
"sourceRoot": "apps/mfe1/src",
"tags": [],
"targets": {
"build": {
"executor": "@angular-architects/native-federation:build",
"options": {},
"configurations": {
"production": {
"target": "mfe1:esbuild:production"
},
"development": {
"target": "mfe1:esbuild:development",
"dev": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"executor": "@angular-architects/native-federation:build",
"options": {
"target": "mfe1:serve-original:development",
"rebuildDelay": 0,
"dev": true,
"port": 0
}
},
"extract-i18n": {
"executor": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "mfe1:build"
}
},
"lint": {
"executor": "@nx/eslint:lint"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "apps/mfe1/jest.config.ts"
}
},
"esbuild": {
"executor": "@angular-devkit/build-angular:application",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/mfe1",
"index": "apps/mfe1/src/index.html",
"browser": "apps/mfe1/src/main.ts",
"polyfills": ["zone.js", "es-module-shims"],
"tsConfig": "apps/mfe1/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": ["apps/mfe1/src/favicon.ico", "apps/mfe1/src/assets"],
"styles": ["apps/mfe1/src/styles.scss"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve-original": {
"executor": "@angular-devkit/build-angular:dev-server",
"options": {
"port": 4201
},
"configurations": {
"production": {
"buildTarget": "mfe1:esbuild:production"
},
"development": {
"buildTarget": "mfe1:esbuild:development"
}
},
"defaultConfiguration": "development"
}
}
}
I found out the solution, there are 2 possible options
Develop/debug the Microfrontend application (MF1) starting the dev server without Module Federation (nx run project-name:server-original)
In case there's no need to share the library across the microfrontend, add the library name to the skip list in the federation.config.js
skip: [
'test-lib',
'rxjs/ajax',
'rxjs/fetch',
'rxjs/testing',
'rxjs/webSocket',
'@native-federation/mfe1/domain',
'@native-federation/mfe1/feature-content',
// Add further packages you don't need at runtime
]