Die Micro-Frontend-Revolution: Webpack 5 Module Federation

Seite 2: Teilen von Abhängigkeiten

Inhaltsverzeichnis

Es ist sehr wahrscheinlich, dass mehrere Remotes und Hosts von denselben Bibliotheken abhängen. Glücklicherweise erlaubt Module Federation in diesen Fällen das Teilen dieser Abhängigkeiten, sodass die Anwendung sie nicht mehrfach in den Browser laden muss. Sämtliche zu teilenden Abhängigkeiten sind dazu lediglich in der Konfiguration unter shared einzutragen (s. Abb. 3).

Module Federation erlaubt das Teilen von Bibliotheken zwischen einzelnen Anwendungen (Abb. 3).

Der Host handelt sogar mit sämtlichen Remotes, die beim Programmstart bekannt sind, die zu nutzenden Versionen dieser Bibliotheken aus. Entsprechend der Regeln der Semantischen Versionierung einigen sich der Host und die Remotes standardmäßig auf die höchste kompatible Version der einzelnen Bibliotheken. Verwendet beispielsweise der Host Angular 10 und ein Remote Angular 10.1, fällt die Wahl demnach auf Version 10.1.

Allerdings existieren auch Konstellationen, in denen Module Federation keine höchste kompatible Version identifizieren kann. Da laut Semantic Versioning unterschiedliche Hauptversionen nicht zueinander kompatibel sein müssen, ergibt sich beispielsweise solch eine Konstellation, wenn der Host Angular 10 und der Remote Angular 9 verwendet. Für diese Fälle erlaubt Module Federation jedoch die Konfiguration zahlreicher Fallback-Strategien, die zum Beispiel zum Laden zweier unterschiedlicher Versionen, zur Ausgabe einer Warnung beziehungsweise eines Fehlers oder zum Zurückgreifen auf eine – zumindest offiziell nicht kompatiblen Version – führen.

Zur besseren Veranschaulichung kommt in Abbildung 4 ein einfaches Beispiel zum Einsatz, das ein Micro Frontend in eine Shell lädt, zum Einsatz. Das Micro Frontend, das sich auch ohne Shell ausführen lässt, findet sich hier innerhalb der gestrichelten Linien wieder.

Dieses einfache Beispiel lädt ein Micro Frontend in eine Shell (Abb. 4).

Beide Anwendungen basieren auf Angular. Da das Angular CLI Webpack abstrahiert, kommt die Community-Lösung @angular-architects/module-federation zum Einsatz. Sie bewegt das Webpack unter der Motorhaube der CLI zur Nutzung von Module Federation, indem es dessen Konfiguration anpasst.

Zusätzlich benötigt man auch eine CLI-Version, die auf Webpack 5 basiert. Für dieses Beispiel kam deswegen die Vorab-Version v11.0.0-next.6 zum Einsatz, welche Webpack 5 als Opt-in unterstützt, zum Einsatz. Über npm erfährt man, wie dieser Opt-in durchzuführen ist.

Bei React- oder Vue-Anwendung, die Webpack direkt verwenden, sind diese Überlegungen nicht notwendig. Hier ist lediglich Webpack 5 mit den nachfolgend beschriebenen Einstellungen zu nutzen.

Die Webpack-Konfiguration des Micro Frontend nutzt das ModuleFederationPlugin, um ein Angular-Modul zu veröffentlichen.

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  output: {
    publicPath: "http://localhost:3000/",
    uniqueName: "mfe1"
  },
  optimization: {
    // Only needed to bypass a temporary bug in Angular CLI 11 Beta
    runtimeChunk: false
  },
  plugins: [
    new ModuleFederationPlugin({
      
        // For remotes (please adjust)
        name: "mfe1",
        library: { type: "var", name: "mfe1" },
        filename: "remoteEntry.js",
        exposes: {
            './Module': './projects/mfe1/src/app/flights/flights.module.ts',
        },        
        shared: ["@angular/core", "@angular/common", "@angular/router"]
    })
  ],
};

Dieses Beispiel beschränkt sich auf jene Webpack-Einstellungen, die sich unmittelbar auf Module Federation auswirken. Den Rest generiert, wie in der Angular-Welt üblich, die CLI.

Die Eigenschaft name legt jenen Namen fest, über den die Shell das Micro Frontend später referenzieren kann. Außerdem gibt filename den Namen des zu generierenden Remote Entry an. Die zu teilenden Abhängigkeiten finden sich unter shared.

Jenseits der für das ModuleFederationPlugin hinterlegten Einstellungen, gilt es auch, die Optionen im Abschnitt output zu beachten. Der publicPath legt die URL fest, unter der die Anwendung später zu finden ist. Hierdurch wird bekannt, wo die einzelnen Bundles der Anwendung aber auch deren Assets, zum Beispiel Bilder oder Styles, zu finden sind.

Der uniqueName definiert einen eindeutigen Namen, der in den generierten Bundles den Host oder den Remote repräsentiert. Standardmäßig verwendet Webpack hierzu den Namen aus der package.json. Um Namenskonflikte beim Einsatz von Monorepos mit mehreren Anwendungen zu vermeiden, empfiehlt es sich, den uniqueName manuell festzulegen.