? ? ? ?這是一個極簡化的 Angular 使用@angular-architects/native-federation 插件的微前端示例,只包含一個主應用和一個遠程應用。
完整示例展示
項目結構
federation-simple/
├── host-app/ # 主應用
└── remote-app/ # 遠程應用
創建遠程應用 (remote-app)
?初始化項目
ng new remote-app --standalone --minimal --style=css --routing=false
cd remote-app
npm install @angular-architects/native-federation --save-dev
配置 Native Federation
ng add @angular-architects/native-federation --project remote-app --port 4201
創建遠程組件
編輯 src/app/hello.component.ts:
import { Component } from '@angular/core';@Component({standalone: true,template: `<div style="border: 2px solid blue;padding: 20px;margin: 10px;border-radius: 5px;"><h2>Hello from Remote App!</h2><p>This component is loaded from the remote app</p></div>`
})
export class HelloComponent {}
配置暴露的模塊
編輯 federation.config.js:
module.exports = {name: 'remoteApp',exposes: {'./Hello': './src/app/hello.component.ts'},shared: {'@angular/core': { singleton: true, strictVersion: true },'@angular/common': { singleton: true, strictVersion: true },'rxjs': { singleton: true, strictVersion: true }}
};
創建主應用 (host-app)
初始化項目
ng new host-app --standalone --minimal --style=css --routing=true
cd host-app
npm install @angular-architects/native-federation @angular-architects/module-federation-tools --save-dev
配置 Native Federation
ng add @angular-architects/native-federation --project host-app --port 4200
創建主頁面
編輯 src/app/app.component.ts:
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';@Component({standalone: true,imports: [CommonModule, RouterOutlet],template: `<div style="padding: 20px;"><h1>Host Application</h1><nav><a routerLink="/" style="margin-right: 15px;">Home</a><a routerLink="/remote">Load Remote Component</a></nav><router-outlet></router-outlet></div>`
})
export class AppComponent {}
創建遠程組件加載頁面
創建 src/app/remote.component.ts:
在這里使用了<app-remote-hello> 那這個怎么來的呢?請見下面的關鍵點說明第四點!!!
import { Component, OnInit } from '@angular/core';
import { loadRemoteModule } from '@angular-architects/module-federation';@Component({standalone: true,template: `<div style="margin-top: 20px;"><h2>Remote Component</h2><div *ngIf="loading">Loading remote component...</div><div *ngIf="error" style="color: red;">Failed to load remote component: {{error}}</div><ng-container *ngIf="!loading && !error"><app-remote-hello></app-remote-hello></ng-container></div>`
})
export class RemoteComponent implements OnInit {loading = true;error: string | null = null;async ngOnInit() {try {await loadRemoteModule({remoteEntry: 'http://localhost:4201/remoteEntry.js',remoteName: 'remoteApp',exposedModule: './Hello'});this.loading = false;} catch (err) {this.error = err instanceof Error ? err.message : String(err);this.loading = false;}}
}
配置路由
編輯 src/app/app.routes.ts:
import { Routes } from '@angular/router';
import { RemoteComponent } from './remote.component';export const APP_ROUTES: Routes = [{ path: 'remote', component: RemoteComponent,providers: [// 注冊遠程組件{provide: 'remote-hello',useValue: {remoteEntry: 'http://localhost:4201/remoteEntry.js',remoteName: 'remoteApp',exposedModule: './Hello',componentName: 'Hello'}}]},{ path: '**', redirectTo: 'remote' }
];
配置應用
編輯 src/app/app.config.ts:
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { provideRouter } from '@angular/router';
import { APP_ROUTES } from './app.routes';
import { RemoteComponent } from '@angular-architects/module-federation-tools';export const appConfig: ApplicationConfig = {providers: [provideRouter(APP_ROUTES),importProvidersFrom(RemoteComponent.forRemote({type: 'module',remoteEntry: 'http://localhost:4201/remoteEntry.js',exposedModule: './Hello',componentName: 'Hello'}))]
};
配置 federation
編輯 federation.config.js:?
module.exports = {name: 'hostApp',remotes: {'remoteApp': 'http://localhost:4201/remoteEntry.js'},shared: {'@angular/core': { singleton: true, strictVersion: true },'@angular/common': { singleton: true, strictVersion: true },'@angular/router': { singleton: true, strictVersion: true },'rxjs': { singleton: true, strictVersion: true }}
};
運行應用
- 打開兩個終端窗口
- 在第一個終端中運行遠程應用
- 在第二個終端中運行主應用
- 訪問應用
- 在主應用中,點擊 "Load Remote Component" 鏈接將加載并顯示遠程組件
關鍵點說明
項目簡單說明下面三點:
-
遠程應用: remote中暴露一個了簡單的HelloCompoent并且配置了共享的 Angular 核心庫;
-
主應用: host中使用 了loadRemoteModule動態加載遠程組件,同時通過路由導航到遠程組件,并且配置了遠程模塊的引用;
-
共享依賴: remote項目和Host項目Angular 核心庫和 RxJS 被標記為共享單例,并且確保了版本兼容性
-
<app-remote-hello> 這個selector怎么來的
app-remote-hello
?是自定義元素,通過下面的方式創建和使用的:
組件名稱的生成規則: 當使用?@angular-architects/module-federation-tools
?的?RemoteComponent
時,組件名稱會自動按照以下規則生成:
app-remote-<componentName>
app
?是 Angular 默認的前綴remote
?表示這是一個遠程組件<componentName>
?是你在配置中指定的組件名稱(這里是?hello
)
具體配置來源:在示例中,這個名稱來源于下面幾個地方的配置:
在?app.config.ts
?中:
importProvidersFrom(RemoteComponent.forRemote({type: 'module',remoteEntry: 'http://localhost:4201/remoteEntry.js',exposedModule: './Hello',componentName: 'Hello' // ← 這里定義了基礎名稱})
)
在?remote.component.ts
?中:
<app-remote-hello></app-remote-hello>
完整的名稱轉換過程:
- 你配置了?
componentName: Hello
- 系統會自動轉換為小寫形式:
hello
- 加上前綴?
app-remote-
?形成最終標簽名:app-remote-hello
如何自定義這個名稱:如果想使用不同的標簽名,可以這樣修改
// 在 app.config.ts 中
RemoteComponent.forRemote({// ...其他配置componentName: 'MyCustomHello', // 自定義名稱elementName: 'my-hello-element' // 自定義元素名(可選)
})// 然后在模板中使用
<my-hello-element></my-hello-element>
為什么能這樣使用:這是因為?@angular-architects/module-federation-tools
?在底層做了以下工作:
-
動態注冊了一個新的 Angular 組件
-
將該組件定義為自定義元素(Custom Element)
-
自動處理了組件名稱的轉換
-
設置了與遠程組件的連接
驗證方法:如果你想確認這個組件是如何被注冊的,可以在瀏覽器開發者工具中:
-
打開 Elements 面板
-
找到?
<app-remote-hello>
?元素 -
查看它的屬性,會發現它是一個 Angular組件
-
-
Angular 組件會有特殊屬性:
-
查看是否有?
_nghost-*
?和?_ngcontent-*
?這類 Angular 特有的屬性 -
例如:
<app-remote-hello _ngcontent-abc="" _nghost-def="">
-
-
檢查自定義元素定義:
-
在 Console 中輸入:
document.querySelector('app-remote-hello').constructor.name
-
如果是 Angular 組件,通常會顯示?
HTMLElement
(因為 Angular 組件最終是自定義元素)
-
-
?參考資料:
核心資源
-
@angular-architects/native-federation 官方文檔
📖?GitHub 倉庫 & 文檔-
包含安裝指南、配置選項和基本用法
-
-
Module Federation 概念解釋
📖?Webpack 官方文檔-
理解微前端的核心機制
-
教程文章
-
Angular 微前端完整指南
📖?Angular Architects 博客-
含代碼示例和架構圖
-
-
實戰案例分步教程
📖?Dev.to 詳細教程-
從零開始的實現步驟
-
視頻資源
-
官方演示視頻
???YouTube 教程-
30分鐘實戰演示(Angular團隊錄制)
-
-
模塊聯邦深度解析
???Webpack 官方頻道-
底層原理講解
-
擴展工具
-
模塊聯邦工具庫
📦?npm @angular-architects/module-federation-tools-
簡化動態加載的工具
-
-
微前端狀態管理方案
📖?NgRx 集成指南-
跨應用狀態管理建議
-
常見問題
-
共享依賴解決方案
??Stack Overflow 熱門討論-
版本沖突處理方案
-
-
生產環境部署指南
📖?Angular 部署文檔-
包含微前端部署注意事項
-
示例代碼庫
-
官方示例項目:可直接運行的完整項目
💻?GitHub 代碼庫