You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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",

解决方案

  1. 补充共享@angular/cdk/portal模块
    MatSelect的下拉选项依赖@angular/cdk/portal模块完成Overlay容器中的渲染,当前共享配置缺少该模块。在Shell和MFE的shared配置中添加:

    "@angular/cdk/portal": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto' },
    
  2. 调整Material组件的共享策略
    尝试暂时移除@angular/material/select和@angular/cdk/overlay的共享配置,让MFE独立打包这些模块,避免单例冲突:

    // 从shared对象中删除以下两行
    // "@angular/material/select": { ... },
    // "@angular/cdk/overlay": { ... },
    
  3. 确认组件变量的可访问性
    确保Food接口已正确定义,且foods变量为组件的public属性(默认情况下Angular组件类属性为public,但若手动设置为private则会导致模板无法访问)。

  4. 清理缓存并重启服务
    删除Shell和MFE的node_modules、dist文件夹,重新执行npm install,然后重启开发服务,避免ModuleFederation的缓存导致模块加载异常。

内容的提问来源于stack exchange,提问作者André von Glehn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:02:01