Angular Module Federation本地IIS生产部署404问题求助
Module Federation独立部署与路由404问题解决方案
核心结论
Module Federation完全支持远程应用独立部署,你的理解没有问题——官方文档示例只是同站点部署的场景,并非唯一实现方式。你遇到的localhost:6001/shop等路由404,是因为host应用的路由配置和IIS服务器规则未匹配Module Federation的组件加载逻辑,而非MF本身不支持独立部署。
问题根源分析
访问localhost:6001/shop时,请求会直接发给host的IIS服务器,但:
- Host的Angular路由中未配置对应路径的远程组件加载规则;
- IIS默认会把这类路径当作静态文件或目录查找,找不到就返回404,不会转发给Angular的SPA路由系统。
分步解决方案
1. 确保远程应用正确暴露路由组件
每个remote应用需要在自己的module-federation.config.js中,将路由模块或根组件暴露出去,供host加载:
// remote shop的module-federation.config.js module.exports = { name: 'shop', exposes: { './ShopRoutes': './src/app/shop/shop.routes.ts', // 暴露路由模块 './ShopRoot': './src/app/shop/shop.component.ts' // 可选:暴露根组件 }, shared: { // 共享依赖配置(如@angular/core等,和host保持一致) } };
cart、about应用做同样配置,替换对应名称即可。
2. Host应用配置远程路由惰性加载
在host的app-routing.module.ts中,使用NX提供的loadRemoteModule方法,通过Module Federation加载远程应用的路由:
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { loadRemoteModule } from '@nx/angular/mf'; const routes: Routes = [ // 本地路由 { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) }, // 远程应用路由配置 { path: 'shop', loadChildren: () => loadRemoteModule({ remoteName: 'shop', exposedModule: './ShopRoutes', }).then(m => m.ShopRoutesModule) // 对应remote暴露的路由模块类名 }, { path: 'cart', loadChildren: () => loadRemoteModule({ remoteName: 'cart', exposedModule: './CartRoutes', }).then(m => m.CartRoutesModule) }, { path: 'about', loadChildren: () => loadRemoteModule({ remoteName: 'about', exposedModule: './AboutRoutes', }).then(m => m.AboutRoutesModule) }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
3. 配置IIS的SPA路由重写规则
无论是host还是每个remote应用,都需要在IIS站点的web.config中添加URL重写规则,确保所有非静态资源的请求都转发到index.html,让Angular路由系统处理:
<configuration> <system.webServer> <rewrite> <rules> <rule name="Angular SPA Routes" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> </conditions> <action type="Rewrite" url="/index.html" /> </rule> </rules> </rewrite> </system.webServer> </configuration>
4. 优化Host的Remotes配置(可选)
你当前的数组形式配置是可行的,但改用对象形式可以更明确指定remoteEntry.mjs的路径,避免潜在的路径解析问题:
module.exports = withModuleFederation({ ...moduleFederationConfig, remotes: { shop: 'http://localhost:6002/remoteEntry.mjs', cart: 'http://localhost:6003/remoteEntry.mjs', about: 'http://localhost:6004/remoteEntry.mjs', }, });
内容的提问来源于stack exchange,提问作者Yogurtu
相关产品推荐
相关产品推荐

