Angular微前端(ModuleFederationPlugin)中mat-select选项不渲染问题
Angular 13微前端中MatSelect下拉选项无法渲染的问题
问题概述
使用Angular 13结合ModuleFederationPlugin构建微前端应用,微前端(MFE)已导入MatSelectModule、MatFormFieldModule、CommonModule及FormsModule等必要模块,Shell应用与MFE均配置了共享模块。其他Angular Material组件正常工作,但MFE中的mat-select无法渲染下拉选项,而Shell应用中该组件可正常使用。
MFE模块导入代码
import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatChipsModule } from '@angular/material/chips'; import { MatNativeDateModule, MAT_DATE_LOCALE } from '@angular/material/core'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatRadioModule } from '@angular/material/radio'; import { MatSelectModule } from '@angular/material/select'; import { MatSidenavModule } from '@angular/material/sidenav'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatSortModule } from '@angular/material/sort'; import { MatTableModule } from '@angular/material/table'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterModule } from '@angular/router'; import { SharedModule } from '../shared/shared.module'; import { RevisarInteiroteorAcordaoComponent } from './acordao/acordao.component'; import { RevisarAtaJulgamentoComponent } from './ata/ata.component'; import { ConsultaJulgamentoComponent } from './consulta/consulta.component'; import { DECISOES_COLEGIADAS_ROUTES } from './julgamentos.routes'; import { ResultadoModule } from './resultado/resultado.module'; import { ConfirmarRealizacaoSessaoComponent } from './sessao/sessao.component'; import { DetalhesSessaoComponent } from './sessoes/detalhes-sessao/detalhes-sessao.component'; import { SessoesModule } from './sessoes/sessoes.module'; import { TabelaComponent } from './sessoes/tabela/tabela.component';
MFE共享配置
plugins: [ new ModuleFederationPlugin({ library: { type: "module" }, name: "colegiadas", filename: "remoteEntry.js", exposes: { }, shared: share({ "@angular/core": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/common": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/common/http": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/router": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/forms": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/animations": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/menu": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/button": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/form-field": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/icon": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/tree": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/input": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/radio": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/select": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/slide-toggle": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/sidenav": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/datepicker": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/dialog": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/autocomplete": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/platform-browser/animations": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/cdk/overlay": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, ...sharedMappings.getDescriptors() })
Shell应用共享配置
plugins: [ new ModuleFederationPlugin({ library: { type: "module" }, shared: share({ "@angular/core": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/common": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/common/http": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/router": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/forms": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/animations": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/menu": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/button": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/form-field": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/icon": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/tree": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/input": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/radio": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/select": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/slide-toggle": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/sidenav": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/datepicker": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/dialog": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/material/autocomplete": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/platform-browser/animations": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, "@angular/cdk/overlay": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' }, ...sharedMappings.getDescriptors() }) }), sharedMappings.getPlugin() ],
示例代码
模板代码
<div> <mat-form-field appearance="fill"> <mat-label>Favorite food</mat-label> <mat-select> <mat-option *ngFor="let food of foods" [value]="food.value"> {{food.viewValue}} </mat-option> </mat-select> </mat-form-field> </div> <div> <mat-form-field appearance="fill"> <mat-label>Choose a technology</mat-label> <mat-select> <mat-option [value]="'pizza'"> pizza </mat-option> <mat-option [value]="'burger'">burger</mat-option> </mat-select> </mat-form-field> </div>
组件数据定义
interface Food { value: string; viewValue: string; } foods: Food[] = [ {value: 'steak-0', viewValue: 'Steak'}, {value: 'pizza-1', viewValue: 'Pizza'}, {value: 'tacos-2', viewValue: 'Tacos'}, ];
实际渲染结果
<mat-select role="combobox" aria-autocomplete="none" aria-haspopup="true" class="mat-select ng-tns-c193-18 ng-tns-c45-17 mat-select-empty ng-star-inserted" aria-labelledby="mat-form-field-label-11 mat-select-value-5" id="mat-select-4" tabindex="0" aria-expanded="false" aria-required="false" aria-disabled="false" aria-invalid="false"> <div cdk-overlay-origin="" class="mat-select-trigger ng-tns-c193-18"> <div class="mat-select-value ng-tns-c193-18" ng-reflect-ng-switch="true" id="mat-select-value-5"> <span class="mat-select-placeholder mat-select-min-line ng-tns-c193-18 ng-star-inserted"></span> <!--bindings={ "ng-reflect-ng-switch-case": "true" }--> <!--bindings={ "ng-reflect-ng-switch-case": "false" }--> </div> <div class="mat-select-arrow-wrapper ng-tns-c193-18"> <div class="mat-select-arrow ng-tns-c193-18"></div> </div> </div> <!--bindings={ "ng-reflect-offset-y": "0" }--> </mat-select>
依赖版本
"@angular-architects/module-federation": "^14.0.2", "@angular/animations": "13.1.1", "@angular/cdk": "13.1.1", "@angular/common": "13.1.1", "@angular/compiler": "13.1.1", "@angular/core": "13.1.1", "@angular/forms": "13.1.1", "@angular/material": "13.1.1",
解决方案
补充共享@angular/cdk/portal模块
MatSelect的下拉选项依赖@angular/cdk/portal模块完成Overlay容器中的渲染,当前共享配置缺少该模块。在Shell和MFE的shared配置中添加:"@angular/cdk/portal": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' },调整Material组件的共享策略
尝试暂时移除@angular/material/select和@angular/cdk/overlay的共享配置,让MFE独立打包这些模块,避免单例冲突:// 从shared对象中删除以下两行 // "@angular/material/select": { ... }, // "@angular/cdk/overlay": { ... },确认组件变量的可访问性
确保Food接口已正确定义,且foods变量为组件的public属性(默认情况下Angular组件类属性为public,但若手动设置为private则会导致模板无法访问)。清理缓存并重启服务
删除Shell和MFE的node_modules、dist文件夹,重新执行npm install,然后重启开发服务,避免ModuleFederation的缓存导致模块加载异常。
内容的提问来源于stack exchange,提问作者André von Glehn
相关产品推荐
相关产品推荐

