Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Micro Frontend - A platform with a different configuration has been created. Please destroy it first #47

Closed
saikmadana opened this issue May 17, 2021 · 5 comments

Comments

@saikmadana
Copy link

I am trying to build a POC for Micro Frontend using Angular and Webpack Module Federation. In this, I have created a shell app and another mfe1 app and rendering that mfe1 on a specific route hit and it is working as expected and rendering the app. Now, I am trying to create another app called mfe2 and render it. In this mfe2, I am creating a web component using Angular elements and rendering that in the shell app. When I do that, I am facing the following issue

Error: A platform with a different configuration has been created. Please destroy it first.

image

when the following code is executing

import('mfe2/web-component')
    .then(_ => console.debug(`element loaded!`))
    .catch(err => console.error(`error loading `, err));

I don't understand where the exact issue is. I am adding the required code below.

MFE2:

app.module.ts

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: []
})
export class AppModule {
  constructor(private injector: Injector) {}

  ngDoBootstrap() {
    const ce = createCustomElement(AppComponent, {injector: this.injector});
    customElements.define('mfe2-elem', ce);
  }

}

webpack.config.js

module.exports = {
  output: {
    uniqueName: "mfe2",
    publicPath: "auto"
  },
  optimization: {
    runtimeChunk: false
  },   
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  plugins: [
    new ModuleFederationPlugin({
      
        // For remotes (please adjust)
        name: "mfe2",
        filename: "remoteEntry.js",
        exposes: {
          './web-component': './src/bootstrap.ts',
        },        
        
        // For hosts (please adjust)
        // remotes: {
        //     "mfe1": "mfe1@http://localhost:3000/remoteEntry.js",

        // },

        shared: {
          "@angular/core": { singleton: true, strictVersion: true }, 
          "@angular/common": { singleton: true, strictVersion: true }, 
          "@angular/common/http": { singleton: true, strictVersion: true }, 
          "@angular/router": { singleton: true, strictVersion: true },

          ...sharedMappings.getDescriptors()
        }
        
    }),
    sharedMappings.getPlugin()
  ],
};

SHELL:

rendering it in a component:

@Component({
  selector: 'app-mfe2element',
  templateUrl: './mfe2element.component.html',
  styleUrls: ['./mfe2element.component.scss']
})
export class Mfe2elementComponent implements AfterContentInit {

  @ViewChild('vc', { read: ElementRef, static: true })
  vc!: ElementRef;

  constructor() { }

  ngAfterContentInit(): void {
    import('mfe2/web-component')
    .then(_ => console.debug(`element loaded!`))
    .catch(err => console.error(`error loading `, err));

    // await import('mfe1/web-components');
    // const element = document.createElement('mfe1-element');
    // document.body.appendChild(element);

    const element = document.createElement('mfe2-elem');
    this.vc.nativeElement.appendChild(element);

  }

}

webpack.config.js

module.exports = {
  output: {
    uniqueName: "shell"
  },
  optimization: {
    // Only needed to bypass a temporary bug
    runtimeChunk: false
  },
  plugins: [
    new ModuleFederationPlugin({
        // For remotes (please adjust)
        // name: "shell",
        // filename: "remoteEntry.js",
        // exposes: {
        //     './Component': './/src/app/app.component.ts',
        // },        
        
        // For hosts (please adjust)
        remotes: {
            "mfe1": "mfe1@http://localhost:3000/remoteEntry.js",
            "mfe2": "mfe2@http://localhost:4000/remoteEntry.js",
        },

        shared: {
          "@angular/core": { singleton: true, strictVersion: false }, 
          "@angular/common": { singleton: true, strictVersion: false }, 
          "@angular/router": { singleton: true, strictVersion: false },

          ...sharedMappings.getDescriptors()
        }
        
    }),
    sharedMappings.getPlugin(),
  ],
};

Please help me solve this issue.

Thanks...

@kbleeck
Copy link

kbleeck commented May 20, 2021

From https://www.angulararchitects.io/aktuelles/multi-framework-and-version-micro-frontends-with-module-federation-the-good-the-bad-the-ugly/:

Per shared Angular version, we are only allowed to create one platform. To remember that there is already a shared platform for our version, we could put it into a global dictionary mapping the version number to the platform instance:

const ngVersion = require('../package.json').dependencies['@angular/core']; // better just take the major version 

(window as any).plattform = (window as any).plattform || {};
let platform = (window as any).plattform[ngVersion];
if (!platform) {
  platform = platformBrowser();
  (window as any).plattform[ngVersion] = platform; 
}
platform.bootstrapModule(AppModule)
  .catch(err => console.error(err));

Adding this to the bootstrap.ts in both the shell and mfe will make the mfe reuse an existing platform instead of trying to create a new instance, which will lead to the error you're experiencing.

@saikmadana
Copy link
Author

Thanks, @kbleeck that worked.

@manfredsteyer
Copy link
Contributor

Thanks, @kbleeck for this pointer.

@gs-rthati
Copy link

@saikumar-madana Areyy sai ga... dorikaav ikkada... :D

Rammurthy

@rikersbeard
Copy link

rikersbeard commented Apr 18, 2024

Was this remedied for later versions > 12?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants