Skip to content

Commit 23aabf7

Browse files
authored
fix(module-federation): ensure angular rspack module federation supports live reload (#33137)
## Current Behavior Angular Rspack outputs to CJS for Module Federation. It also has potential issues to cause infinite live reload loops. ## Expected Behavior Angular Rspack with Module Federation should work as expected This PR also adds: - example of Module Federation with Angular Rspack in `examples/angular-rspack/module-federation`
1 parent d01bcb4 commit 23aabf7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1747
-15
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../../../../.eslintrc.json"
3+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module.exports = {
2+
name: 'examples-angular-rspack-mf-host',
3+
/**
4+
* To use a remote that does not exist in your current Nx Workspace
5+
* You can use the tuple-syntax to define your remote
6+
*
7+
* remotes: [['my-external-remote', 'https://nx-angular-remote.netlify.app']]
8+
*
9+
* You _may_ need to add a `remotes.d.ts` file to your `src/` folder declaring the external remote for tsc, with the
10+
* following content:
11+
*
12+
* declare module 'my-external-remote';
13+
*
14+
*/
15+
remotes: ['examples-angular-rspack-mf-remote'],
16+
shared: (libraryName) => {
17+
// This is specific to Nx Repo, otherwise dependencies that are irrelevant are considered and shared
18+
if (
19+
!libraryName.startsWith('@angular') &&
20+
!libraryName.startsWith('zone.js')
21+
) {
22+
return false;
23+
}
24+
},
25+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "examples-angular-rspack-mf-host",
3+
"version": "0.0.1",
4+
"private": true,
5+
"scripts": {},
6+
"dependencies": {
7+
"@nx/angular-rspack": "workspace:*"
8+
},
9+
"devDependencies": {
10+
"@nx/module-federation": "workspace:*",
11+
"@rspack/core": "1.5.2",
12+
"@rspack/cli": "1.5.2"
13+
},
14+
"nx": {
15+
"targets": {
16+
"serve": {
17+
"dependsOn": [
18+
"^build"
19+
]
20+
},
21+
"build": {
22+
"dependsOn": [
23+
"^build"
24+
]
25+
}
26+
}
27+
}
28+
}
Binary file not shown.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const {
2+
patchDevkitRequestPath,
3+
patchModuleFederationRequestPath,
4+
} = require('../../patch-devkit-request-path');
5+
module.exports = () => {
6+
if (global.NX_GRAPH_CREATION === undefined) {
7+
// This is needed to ensure that the `@nx/angular-rspack` package can find the build artefact for `@nx/devkit`
8+
// TODO(colum): Remove this once packages in Nx are built to local dist
9+
const {
10+
patchDevkitRequestPath,
11+
patchModuleFederationRequestPath,
12+
} = require('../../patch-devkit-request-path');
13+
const cleanupDevkitPatch = patchDevkitRequestPath();
14+
const cleanupModuleFederationPatch = patchModuleFederationRequestPath();
15+
const {
16+
NxModuleFederationPlugin,
17+
NxModuleFederationDevServerPlugin,
18+
} = require('@nx/module-federation/angular');
19+
const { createConfig } = require('@nx/angular-rspack');
20+
const mfConfig = require('./module-federation.config');
21+
const config = createConfig(
22+
{
23+
options: {
24+
root: __dirname,
25+
outputPath: {
26+
base: './dist',
27+
browser: './browser',
28+
},
29+
index: './src/index.html',
30+
browser: './src/main.ts',
31+
tsConfig: './tsconfig.app.json',
32+
polyfills: ['zone.js'],
33+
assets: [{ glob: '**/*', input: 'public' }],
34+
statsJson: true,
35+
styles: ['./src/styles.scss'],
36+
},
37+
rspackConfigOverrides: {
38+
plugins: [
39+
new NxModuleFederationPlugin(
40+
{ config: mfConfig },
41+
{
42+
dts: false,
43+
}
44+
),
45+
new NxModuleFederationDevServerPlugin({ config: mfConfig }),
46+
],
47+
},
48+
},
49+
{
50+
development: {
51+
options: {
52+
extractLicenses: false,
53+
optimization: false,
54+
outputHashing: 'none',
55+
namedChunks: true,
56+
vendorChunk: true,
57+
devServer: {
58+
/**
59+
* These values MUST be set to ensure that the webSocketSettings within the devServer config is configured to
60+
* only listen for updates to this specific project. Otherwise, a live reload loop could be created.
61+
*/
62+
publicHost: 'localhost:4200',
63+
port: 4200,
64+
},
65+
},
66+
},
67+
production: {
68+
options: {
69+
extractLicenses: false,
70+
outputHashing: 'all',
71+
optimization: {
72+
scripts: true,
73+
styles: {
74+
minify: false,
75+
inlineCritical: true,
76+
},
77+
},
78+
},
79+
},
80+
}
81+
);
82+
cleanupDevkitPatch();
83+
cleanupModuleFederationPatch();
84+
return config;
85+
}
86+
return {};
87+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {
2+
ApplicationConfig,
3+
provideBrowserGlobalErrorListeners,
4+
provideZoneChangeDetection,
5+
} from '@angular/core';
6+
import { provideRouter } from '@angular/router';
7+
import { appRoutes } from './app.routes';
8+
9+
export const appConfig: ApplicationConfig = {
10+
providers: [
11+
provideBrowserGlobalErrorListeners(),
12+
provideZoneChangeDetection({ eventCoalescing: true }),
13+
provideRouter(appRoutes),
14+
],
15+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<h1>Hello world!</h1>
2+
<ul>
3+
<li routerLink="remote">Remote</li>
4+
</ul>
5+
<router-outlet></router-outlet>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Route } from '@angular/router';
2+
3+
export const appRoutes: Route[] = [
4+
{
5+
path: 'remote',
6+
loadChildren: () =>
7+
// @ts-expect-error
8+
import('examples-angular-rspack-mf-remote/Routes').then(
9+
(m) => m!.remoteRoutes
10+
),
11+
},
12+
];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Component } from '@angular/core';
2+
import { RouterModule } from '@angular/router';
3+
4+
@Component({
5+
imports: [RouterModule],
6+
selector: 'app-root',
7+
templateUrl: './app.html',
8+
})
9+
export class App {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { bootstrapApplication } from '@angular/platform-browser';
2+
import { appConfig } from './app/app.config';
3+
import { App } from './app/app';
4+
5+
bootstrapApplication(App, appConfig).catch((err) => console.error(err));

0 commit comments

Comments
 (0)