2

My application uses microfrontends usind the ModuleFederationPlugin from angular 13. The MatSelectModule, MatFormField and CommonModule and FormsModule are imported normaly in the microfrontend (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';

Both the shell and the mfe imports the shared modules:

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()
            })

The shell import

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()
  ],

All other material-angular components works fine.

The mat-select works fine in the shell, but do not work in the mfe. It simply did not render the options in the mfe. Here is quite a simple example.

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

The first example has the equivalent in the component.

foods: Food[] = [
    {value: 'steak-0', viewValue: 'Steak'},
    {value: 'pizza-1', viewValue: 'Pizza'},
    {value: 'tacos-2', viewValue: 'Tacos'},
  ];

The html simply do have the options

enter image description here

The rendered (not rendered actually) element:

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

I´m using:

"@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 Answers1

1

Since @angular/material depends on @angular/animations, @angular/cdk, @angular/core, @angular/common, @angular/forms and @angular/platform-browser (Source), you should also include these dependencies on the share block. Note that you're explicitly sharing some of the secondary entrypoints of @angular/material, @angular/cdk and @angular/platform-browser (e.g. @angular/material/menu, @angular/cdk/overlay, @angular/platform-browser/animations). Altough that might work, you would have to track each possible dependency with a secondary entrypoint.

That way, it's usually easier to manage those dependecies by sharing the primary entrypoint (e.g. @angular/cdk, @angular/platform-browser) and set the includeSecondaries to true):

      "@angular/material": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
      "@angular/platform-browser": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },
      "@angular/cdk": { eager: true, singleton: true, strictVersion: true, requiredVersion: 'auto', includeSecondaries: true },

Note: 'includeSecondaries: true' is optional starting with Module Federation v14.3, because now true is its default value.(https://www.angulararchitects.io/aktuelles/whats-new-in-angular-architects-module-federation-14-3/)