diff --git a/module-federation-vite-angular/host/package.json b/module-federation-vite-angular/host/package.json index 4104c641e6..bdc721ea8d 100644 --- a/module-federation-vite-angular/host/package.json +++ b/module-federation-vite-angular/host/package.json @@ -9,24 +9,24 @@ "preview": "vite preview --port 5173" }, "dependencies": { - "@angular/animations": "^18.0.0", - "@angular/build": "^18.0.0", - "@angular/common": "^18.0.0", - "@angular/compiler": "^18.0.0", - "@angular/core": "^18.0.0", - "@angular/platform-browser": "^18.0.0", - "@angular/platform-browser-dynamic": "^18.0.0", - "@angular/platform-server": "^18.0.0", - "@module-federation/vite": "1.11.0", - "rxjs": "~7.8.0", - "tslib": "^2.3.0", - "zone.js": "~0.14.3" + "@angular/animations": "^20.3.18", + "@angular/common": "^20.3.18", + "@angular/compiler": "^20.3.18", + "@angular/core": "^20.3.18", + "@angular/platform-browser": "^20.3.18", + "@angular/platform-browser-dynamic": "^20.3.18", + "@angular/platform-server": "^20.3.18", + "@module-federation/vite": "1.13.5", + "rxjs": "~7.8.2", + "tslib": "^2.8.1", + "zone.js": "~0.15.1" }, "devDependencies": { - "@analogjs/vite-plugin-angular": "^1.7.3", - "@angular/build": "^18.0.0", - "@angular/compiler-cli": "^18.0.0", - "typescript": "5.4.5", - "vite": "^5.4.1" + "@analogjs/vite-plugin-angular": "^2.3.1", + "@angular/build": "^20.3.21", + "@angular/compiler-cli": "^20.3.18", + "@module-federation/dts-plugin": "^2.2.3", + "typescript": "5.9.3", + "vite": "^7.3.1" } -} +} \ No newline at end of file diff --git a/module-federation-vite-angular/host/src/app.component.ts b/module-federation-vite-angular/host/src/app.component.ts index cbc072b6dc..ba910aae83 100644 --- a/module-federation-vite-angular/host/src/app.component.ts +++ b/module-federation-vite-angular/host/src/app.component.ts @@ -1,5 +1,14 @@ +import { + Component, + EnvironmentInjector, + ViewContainerRef, + effect, + inject, + runInInjectionContext, + viewChild, +} from '@angular/core'; + import { CommonModule } from '@angular/common'; -import { Component, effect, viewChild, ViewContainerRef } from '@angular/core'; import { CounterComponent } from './counter.component'; @Component({ @@ -31,12 +40,27 @@ import { CounterComponent } from './counter.component'; imports: [CommonModule, CounterComponent], }) export class AppComponent { + private readonly environmentInjector = inject(EnvironmentInjector); + private remoteLoadStarted = false; + viewContainer = viewChild('remote_app', { read: ViewContainerRef }); constructor() { - effect(async () => { - const m = await import('remote/remote-app'); - this.viewContainer()?.createComponent(m.AppComponent); + effect(() => { + const vc = this.viewContainer(); + if (!vc || this.remoteLoadStarted) { + return; + } + this.remoteLoadStarted = true; + + void import('remote/remote-app').then(m => { + runInInjectionContext(this.environmentInjector, () => { + vc.createComponent(m.AppComponent, { + environmentInjector: this.environmentInjector, + injector: vc.injector, + }); + }); + }); }); } -} +} \ No newline at end of file diff --git a/module-federation-vite-angular/host/vite.config.ts b/module-federation-vite-angular/host/vite.config.ts index 5a7743bcd9..0d0d2dae64 100644 --- a/module-federation-vite-angular/host/vite.config.ts +++ b/module-federation-vite-angular/host/vite.config.ts @@ -1,31 +1,50 @@ +import type { PluginOption, UserConfig } from 'vite'; + import angular from '@analogjs/vite-plugin-angular'; -import { federation } from '@module-federation/vite'; import { defineConfig } from 'vite'; +import { federation } from '@module-federation/vite'; + +/** MF sets optimizeDeps.force=true; that re-runs prebundling every dev start and causes 504 Outdated Optimize Dep races (see module-federation/vite#376). */ +function clearOptimizeDepsForce(): PluginOption { + return { + name: 'clear-mf-optimize-deps-force', + enforce: 'post', + config: () => ({ + optimizeDeps: { force: false }, + }), + }; +} // https://vitejs.dev/config/ -export default defineConfig(({ mode }) => ({ - build: { - target: 'chrome89', - }, - resolve: { - mainFields: ['module'], - }, - plugins: [ - federation({ - name: 'host', - remotes: { - remote: { - type: 'module', - name: 'remote', - entry: 'http://localhost:5174/remoteEntry.js', - entryGlobalName: 'remote', - shareScope: 'default', +export default defineConfig( + (): UserConfig => ({ + build: { + target: 'chrome89', + }, + resolve: { + mainFields: ['module'], + dedupe: ['@angular/core'], + }, + plugins: [ + federation({ + name: 'host', + remotes: { + remote: { + type: 'module', + name: 'remote', + entry: 'http://localhost:5174/remoteEntry.js', + entryGlobalName: 'remote', + shareScope: 'default', + }, }, - }, - exposes: {}, - filename: 'remoteEntry.js', - shared: ['@angular/core'], - }), - angular(), - ], -})); + exposes: {}, + filename: 'remoteEntry.js', + shared: ['@angular/core'], + // DTS pulls @module-federation/dts-plugin into remoteEntry via optimized deps → frequent 504 when cache invalidates. + dts: false, + }) as unknown as PluginOption, + angular() as unknown as PluginOption, + clearOptimizeDepsForce(), + ], + }), +); \ No newline at end of file diff --git a/module-federation-vite-angular/remote/package.json b/module-federation-vite-angular/remote/package.json index ed0d996a94..06fb87d5b6 100644 --- a/module-federation-vite-angular/remote/package.json +++ b/module-federation-vite-angular/remote/package.json @@ -9,24 +9,24 @@ "preview": "vite preview --port 5174" }, "dependencies": { - "@angular/animations": "^18.0.0", - "@angular/build": "^18.0.0", - "@angular/common": "^18.0.0", - "@angular/compiler": "^18.0.0", - "@angular/core": "^18.0.0", - "@angular/platform-browser": "^18.0.0", - "@angular/platform-browser-dynamic": "^18.0.0", - "@angular/platform-server": "^18.0.0", - "@module-federation/vite": "1.11.0", - "rxjs": "~7.8.0", - "tslib": "^2.3.0", - "zone.js": "~0.14.3" + "@angular/animations": "^20.3.18", + "@angular/common": "^20.3.18", + "@angular/compiler": "^20.3.18", + "@angular/core": "^20.3.18", + "@angular/platform-browser": "^20.3.18", + "@angular/platform-browser-dynamic": "^20.3.18", + "@angular/platform-server": "^20.3.18", + "@module-federation/vite": "1.13.5", + "rxjs": "~7.8.2", + "tslib": "^2.8.1", + "zone.js": "~0.15.1" }, "devDependencies": { - "@analogjs/vite-plugin-angular": "^1.7.3", - "@angular/build": "^18.0.0", - "@angular/compiler-cli": "^18.0.0", - "typescript": "5.4.5", - "vite": "^5.4.1" + "@analogjs/vite-plugin-angular": "^2.3.1", + "@angular/build": "^20.3.21", + "@angular/compiler-cli": "^20.3.18", + "@module-federation/dts-plugin": "^2.2.3", + "typescript": "5.9.3", + "vite": "^7.3.1" } -} +} \ No newline at end of file diff --git a/module-federation-vite-angular/remote/vite.config.ts b/module-federation-vite-angular/remote/vite.config.ts index 123f84fda1..c47bd3febc 100644 --- a/module-federation-vite-angular/remote/vite.config.ts +++ b/module-federation-vite-angular/remote/vite.config.ts @@ -1,25 +1,43 @@ +import type { PluginOption, UserConfig } from 'vite'; + import angular from '@analogjs/vite-plugin-angular'; -import { federation } from '@module-federation/vite'; import { defineConfig } from 'vite'; +import { federation } from '@module-federation/vite'; -// https://vitejs.dev/config/ -export default defineConfig(({ mode }) => ({ - build: { - target: 'chrome89', - }, - resolve: { - mainFields: ['module'], - }, - plugins: [ - federation({ - filename: 'remoteEntry.js', - name: 'remote', - exposes: { - './remote-app': './src/app.component.ts', - }, - remotes: {}, - shared: ['@angular/core'], +/** MF sets optimizeDeps.force=true; that re-runs prebundling every dev start and causes 504 Outdated Optimize Dep races (see module-federation/vite#376). */ +function clearOptimizeDepsForce(): PluginOption { + return { + name: 'clear-mf-optimize-deps-force', + enforce: 'post', + config: () => ({ + optimizeDeps: { force: false }, }), - angular(), - ], -})); + }; +} + +// https://vitejs.dev/config/ +export default defineConfig( + (): UserConfig => ({ + build: { + target: 'chrome89', + }, + resolve: { + mainFields: ['module'], + dedupe: ['@angular/core'], + }, + plugins: [ + federation({ + filename: 'remoteEntry.js', + name: 'remote', + exposes: { + './remote-app': './src/app.component.ts', + }, + remotes: {}, + shared: ['@angular/core'], + dts: false, + }) as unknown as PluginOption, + angular() as unknown as PluginOption, + clearOptimizeDepsForce(), + ], + }), +); \ No newline at end of file