feat: add micro-frontend example using @module-federation/vite#169
Conversation
…#168) - Add apps/counter-remote as MFE remote (port 4201, exposes ./Routes) - Configure @module-federation/vite 1.16.2 on both host and remote - Use federation() plugin disabled in test mode to avoid Vitest conflicts - Add mfe-counter route to web-app using dynamic import('counter-remote/Routes') - Add MFE Counter nav link in shared nav-links - Add TypeScript module declaration for counter-remote/Routes - Externalize virtual:pwa-register in remote build (tree-shaken, not instantiated) - Set chrome89 build target on both host and remote for top-level await support - Add passWithNoTests + tsconfig.spec.json to counter-remote for empty test suite - Known limitation: LayoutStore singleton — remote bundles its own copy of @myorg/shared, so nav title won't update when loaded as MFE (workspace libs cannot be in MF shared config, only npm packages) - Demo targets nx serve (dev mode); @module-federation/vite issue #707 (async __loadShare__ wrappers) may affect production builds with ng-content components Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
…ibility @module-federation/vite crashes when server.watch is boolean false. The @nx/vite build executor defaults watch to false, which gets merged into the inline config before plugin config hooks run. A pre-enforce plugin ensures server.watch is an object before the federation hook sees it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
- Add counter-remote:serve to web-app serve dependsOn - Add continuous: true to counter-remote serve target - Add normalize-server-watch plugin to counter-remote vite config Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
The host provides virtual:pwa-register via vite-plugin-pwa, but the remote's dev server pre-transforms shared libs independently and can't resolve it. A no-op virtual plugin stubs it out so the dev server starts cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
Both host and remote were bundling separate copies of @ngrx/signals, creating duplicate DI token identities for platform-scoped services (Dispatcher, Events, ReducerEvents). Angular's DI detected this as a circular dependency (NG0200) when the SignalStore-based CounterStore was instantiated via the MFE route. Sharing @ngrx/signals and @ngrx/signals/events as singletons ensures a single set of class tokens across the federation boundary, fixing the circular dependency error on navigation to /mfe-counter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
Prevents NG0912 component ID collision warnings by ensuring all Angular CDK and Material sub-path packages, plus workspace libs (@myorg/counter, @myorg/shared), are shared as singletons in both host and remote vite configs. Previously only core Angular packages were shared, causing CDK/Material components and workspace-lib components to be bundled separately in each app and registered twice with Angular's component ID registry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tion) MF virtual modules can't enumerate export * chains from TypeScript path aliases, causing [MISSING_EXPORT] build errors. Workspace libs must remain as separate bundles in each app. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…red singletons Both @angular/material/divider and @angular/material/sidenav are imported by workspace libs (@myorg/shared) which are loaded by both the host and remote. Adding them as singletons prevents NG0912 component ID collisions for MatDivider, MatSidenav, etc. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
- add counter-remote app exposing counter lib via module federation - fix NG0912 collisions: import:false on CDK/Material in remote sharedDeps - fix test OXC failures: fastCompile:mode==='test' in host analog() call (angular files outside tsconfig.spec.json compiled by fast-compile AOT; non-Angular TS stripped by OXC lang:'ts' instead of lang:'js') - remove /feature duplicate route; /mfe-counter is the single MFE entry - update README with MFE architecture section - add .claude/skills/create-mfe SKILL.md documenting the full setup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Azure Static Web Apps allows at most one '*' per route pattern. Replace '/counter-remote/**' with two single-wildcard patterns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bump actions/checkout and actions/setup-node from v4 to v6 in preview.yml and deploy.yml to avoid Node.js 20 deprecation warnings. Also align actions/setup-dotnet to v5 in deploy.yml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
- counter-remote-routes.ts: re-export counterRoutes directly from @myorg/counter instead of importing CounterContainer (which is not in the lib's barrel export), fixing NG04014 in CI integration tests - E2E tests: update URL assertions from /feature to /mfe-counter - playwright.config.ts: add counter-remote:serve webServer so MFE remote is available during E2E runs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
In preview.yml the copy step ran before web-app build, so the build wipe wiped the counter-remote files. Fix: build both apps first, then copy counter-remote into web-app/client/counter-remote/. In deploy.yml counter-remote was never built or deployed at all. Add build + copy steps and set COUNTER_REMOTE_ENTRY=/counter-remote/remoteEntry.js so the host resolves the MFE correctly in production. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
- Fix step order: generate lib first, then remote app - Add required barrel export and remotes.d.ts type declaration steps - Clarify remote app shell files must be kept (keep main.ts, app.config.ts etc) - Fix @module-federation/vite placement: devDependencies not dependencies - Add checklist of vite.config.ts fields to update when cloning counter-remote - Fix test stub: prefer re-exporting lib routes over importing components directly (avoids NG04014 when component is not in barrel) - Fix CI build order: copy after BOTH builds, not before host build (host build wipes its output dir, destroying the copied remote files) - Fix SWA wildcards: use /* not /** (SWA only allows one * per segment) - Add E2E section with playwright webServer entries - Add missing pitfalls: NG04014, remote files wiped by host build Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ot level Move CounterStore from component-scoped providers to providedIn: 'root' so the state survives when navigating away from and back to the counter route. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
…ld output Icons in src/assets/icons/ were not being copied to dist because Vite's publicDir defaults to <root>/public, not src/. Moving them to public/assets/icons/ ensures they are served at /assets/icons/*.png in the deployed app, fixing 404s for PWA manifest icons in SWA. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
#168) provideAnimations() from @angular/platform-browser/animations resolves to undefined through the @module-federation/vite loadShare mechanism, causing "TypeError: Ut is not a function" in the deployed preview. Since provideAnimations() is deprecated in Angular 21+ (animations are now provided automatically by the platform), removing the explicit call eliminates the broken loadShare dependency. Also added an MFE integration e2e test that guards against JS load errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
- Removed injectDispatch, eventGroup, on, withReducer from CounterStore - Consolidated into single signalStore with withMethods + patchState - Removed @ngrx/signals/events and @angular/animations from counter-remote shared deps - The root cause: @module-federation/vite generates same loadShare path for @ngrx/signals and @ngrx/signals/events, inlining a separate copy of @angular/core internals (_injectImplementation) that is never set during host DI, causing takeUntilDestroyed() to fail with NG0203. - Updated counter E2E tests: all 31 passed (including MFE integration) - Local verification: counter MFE renders with zero JS errors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…led) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…te too Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Moved pnpm.overrides from package.json to pnpm-workspace.yaml (fixes pnpm 11 deprecation warning & CI lockfile mismatch with --frozen-lockfile) - Updated all 3 CI workflows to pnpm 11 to match local version - Regenerated lockfile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://green-water-08792290f-169.eastus2.2.azurestaticapps.net |
|
Note Coverage shown for affected projects only. Per-file thresholds (80%) are enforced by vitest.
|
Closes #168
Summary
Adds a working micro-frontend (MFE) demo using
@module-federation/vite1.16.2 — the only MFE solution compatible with@analogjs/platform(native federation requires Angular CLI builder, bypassesvite.config.ts).Architecture
apps/web-app(existing Analog app) — addsfederation()as MFE hostapps/counter-remote(new, port 4201) — exposes./Routespointing to the counter feature libWhat was added
apps/counter-remote/— new Vite+Angular app with MFE remote config, exposeslibs/counterroutesapps/web-app/src/types/remotes.d.ts— TypeScript module declaration forcounter-remote/Routes/mfe-counterroute in web-app, loaded viaimport('counter-remote/Routes')Key implementation notes
federation()plugin is disabled in test mode (mode !== 'test') to avoid Vitest crashesvirtual:pwa-registerexternalized in remote build (transitively imported via@myorg/shared, tree-shaken)chrome89build target on both host and remote (required for top-level await)passWithNoTests: truein counter-remote's Vitest config (remote has no spec files yet)Known limitations
@myorg/shared— workspace libs can't be in MFsharedconfig (only npm packages). Nav title won't update when the counter is loaded as an MFE.@module-federation/viteissue #707 (async__loadShare__wrappers) may affect production builds for components using<ng-content>.nx serveworks as expected.