{"id":4186,"date":"2020-06-27T00:06:12","date_gmt":"2020-06-26T22:06:12","guid":{"rendered":"https:\/\/www.angulararchitects.io\/?p=4186"},"modified":"2024-01-19T15:11:42","modified_gmt":"2024-01-19T14:11:42","slug":"dynamic-module-federation-with-angular","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/","title":{"rendered":"Dynamic Module Federation with Angular"},"content":{"rendered":"<div class=\"wp-post-series-box series-module-federation wp-post-series-box--expandable\">\n\t\t\t<input id=\"collapsible-series-module-federation69ec9118e6972\" class=\"wp-post-series-box__toggle_checkbox\" type=\"checkbox\">\n\t\n\t<label\n\t\tclass=\"wp-post-series-box__label\"\n\t\t\t\t\tfor=\"collapsible-series-module-federation69ec9118e6972\"\n\t\t\ttabindex=\"0\"\n\t\t\t\t>\n\t\t<p class=\"wp-post-series-box__name wp-post-series-name\">\n\t\t\tThis is post 3 of 10 in the series <em>&ldquo;Module Federation&rdquo;<\/em>\t\t<\/p>\n\t\t\t<\/label>\n\n\t\t\t<div class=\"wp-post-series-box__posts\">\n\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/the-microfrontend-revolution-module-federation-in-webpack-5\/\">The Microfrontend Revolution: Module Federation in Webpack 5<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/the-microfrontend-revolution-part-2-module-federation-with-angular\/\">The Microfrontend Revolution: Module Federation with Angular<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><span class=\"wp-post-series-box__current\">Dynamic Module Federation with Angular<\/span><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/\">Building A Plugin-based Workflow Designer With Angular and Module Federation<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/getting-out-of-version-mismatch-hell-with-module-federation\/\">Getting Out of Version-Mismatch-Hell with Module Federation<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/using-module-federation-with-monorepos-and-angular\/\">Using Module Federation with (Nx) Monorepos and Angular<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/pitfalls-with-module-federation-and-angular\/\">Pitfalls with Module Federation and Angular<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/multi-framework-and-version-micro-frontends-with-module-federation-your-4-steps-guide\/\">Multi-Framework and -Version Micro Frontends with Module Federation: Your 4 Steps Guide<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/module-federation-with-angulars-standalone-components\/\">Module Federation with Angular&#8217;s Standalone Components<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/whats-new-in-angular-architects-module-federation-14-3\/\">What&#8217;s New in our Module Federation Plugin 14.3?<\/a><\/li>\n\t\t\t\t\t\t\t<\/ol>\n\t\t<\/div>\n\t<\/div>\n<style>\n ul li a { text-decoration: underline!important }<\/style>\n<p>In the <a href=\"https:\/\/www.angulararchitects.io\/aktuelles\/the-microfrontend-revolution-part-2-module-federation-with-angular\/\n\">previous article<\/a> of this series, I've shown how to use Webpack Module Federation for loading separately compiled Micro Frontends into a shell. As the shell's webpack configuration describes the Micro Frontends, we already needed to know them when compiling it.<\/p>\n<\/p>\n<p>In this article, I'm assuming a more dynamic situation where the shell does not know the Micro Frontend upfront. Instead, this information is provided at runtime via a configuration file. While this file is a static JSON file in the examples shown here, it's content could also come from a Web API.<\/p>\n<p><strong>Important<\/strong>: This article is written for Angular and <strong>Angular CLI 14<\/strong> or higher. Make sure you have a fitting version if you try out the examples! For more details on the differences\/ migration to Angular 14 please see this <a href=\"https:\/\/github.com\/angular-architects\/module-federation-plugin\/blob\/main\/migration-guide.md\">migration guide<\/a>.<\/p>\n<p>The following image displays the idea described in this article:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2022\/06\/overview-cli14.png\" alt=\"The shell loads a Micro Frontend it is informed about on runtime\" \/><\/p>\n<p>For all Micro Frontends the shell gets informed about at runtime, it displays a menu item. When clicking it, the Micro Frontend is loaded and displayed by the shell's router.<\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/manfredsteyer\/module-federation-with-angular-dynamic\/tree\/simple\">Source Code (simple version, see branch: simple)<\/a><\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/manfredsteyer\/module-federation-with-angular-dynamic.git\">Source Code (full version)<\/a><\/p>\n<h2>A Simple Dynamic Solution<\/h2>\n<p>Let's start with a simple approach. For this, we assume that we know the Micro Frontends upfront and just want to switch out their URLs at runtime, e. g. with regards to the current environment. A more advanced approach, where we don't even need to know the number of Micro Frontends upfront is presented afterwards.<\/p>\n<h3>Adding Module Federation<\/h3>\n<p>The demo project used contains a shell and two Micro Frontends called <code><code>mfe1<\/code><code> and <\/code><code>mfe2<\/code><\/code>. As in the previous article, we add and initialize the Module Federation plugin for the Micro Frontends:<\/p>\n<pre><code class=\"language-bash\">npm i -g @angular-architects\/module-federation -D\n\n ng g @angular-architects\/module-federation --project mfe1 --port 4201 --type remote\n\n ng g @angular-architects\/module-federation --project mfe2 --port 4202 --type remote<\/code><\/pre>\n<h3>Generating a Manifest<\/h3>\n<p>Beginning with the plugin's version 14.3, we can generate a <strong>dynamic host<\/strong> that takes the key data about the Micro Frontend from a JSON file -- called the Micro Frontend Manifest -- at runtime: <\/p>\n<pre><code class=\"language-bash\">ng g @angular-architects\/module-federation --project shell --port 4200 --type dynamic-host<\/code><\/pre>\n<p>This generates:<\/p>\n<ul>\n<li>a webpack configuration<\/li>\n<li>the manifest and <\/li>\n<li>some code in the <code><code>main.ts<\/code><\/code> loading the manifest.<\/li>\n<\/ul>\n<p>The manifest can be found here: <code><code>projects\/shell\/src\/assets\/mf.manifest.json<\/code><\/code>. This is what it looks like:<\/p>\n<pre><code class=\"language-json\">{\n     &quot;mfe1&quot;: &quot;http:\/\/localhost:4201\/remoteEntry.js&quot;,\n     &quot;mfe2&quot;: &quot;http:\/\/localhost:4202\/remoteEntry.js&quot;\n }<\/code><\/pre>\n<p>After generating the manifest, make sure the ports match.<\/p>\n<h3>Loading the Manifest<\/h3>\n<p>The generated <code><code>main.ts<\/code><\/code> file loads the manifest:<\/p>\n<pre><code class=\"language-typescript\">import { loadManifest } from &#039;@angular-architects\/module-federation&#039;;\n\n loadManifest(&quot;\/assets\/mf.manifest.json&quot;)\n   .catch(err =&gt; console.error(err))\n   .then(_ =&gt; import(&#039;.\/bootstrap&#039;))\n   .catch(err =&gt; console.error(err));<\/code><\/pre>\n<p>By default, <code><code>loadManifest<\/code><\/code> not just loads the manifest but also the remote entries the manifest points to. Hence, Module Federation gets all the required metadata for fetching the Micro Frontends on demand.<\/p>\n<h3>Loading the Micro Frontends<\/h3>\n<p>To load the Micro Frontends described by the manifest, we go with the following routes:<\/p>\n<pre><code class=\"language-typescript\">import { Routes } from &#039;@angular\/router&#039;;\n import { HomeComponent } from &#039;.\/home\/home.component&#039;;\n import { loadRemoteModule } from &#039;@angular-architects\/module-federation&#039;;\n\n export const APP_ROUTES: Routes = [\n     {\n       path: &#039;&#039;,\n       component: HomeComponent,\n       pathMatch: &#039;full&#039;\n     },\n     {\n       path: &#039;flights&#039;,\n       loadChildren: () =&gt; loadRemoteModule({\n           type: &#039;manifest&#039;,\n           remoteName: &#039;mfe1&#039;,\n           exposedModule: &#039;.\/Module&#039;\n         })\n         .then(m =&gt; m.FlightsModule)\n     },\n     {\n       path: &#039;bookings&#039;,\n       loadChildren: () =&gt; loadRemoteModule({\n           type: &#039;manifest&#039;,\n           remoteName: &#039;mfe2&#039;,\n           exposedModule: &#039;.\/Module&#039;\n         })\n         .then(m =&gt; m.BookingsModule)\n     },\n ];<\/code><\/pre>\n<p>The option <code><code>type: &#039;manifest&#039;<\/code><code> makes <\/code><code>loadRemoteModule<\/code><code> to look up the key data needed in the loaded manifest. The property <\/code><code>remoteName<\/code><\/code> points to the key that was used in the manifest.<\/p>\n<h3>Configuring the Micro Frontends<\/h3>\n<p>We expect both Micro Frontends to provide an NgModule with sub routes via <code><code>&#039;.\/Module&#039;<\/code><code>. The NgModules are exposed via the <\/code><code>webpack.config.js<\/code><\/code> in the Micro Frontends:<\/p>\n<pre><code class=\"language-javascript\">\/\/ projects\/mfe1\/webpack.config.js\n\n const { shareAll, withModuleFederationPlugin } = require(&#039;@angular-architects\/module-federation\/webpack&#039;);\n\n module.exports = withModuleFederationPlugin({\n\n   name: &#039;mfe1&#039;,\n\n   exposes: {\n     \/\/ Adjusted line:\n     &#039;.\/Module&#039;: &#039;.\/projects\/mfe1\/src\/app\/flights\/flights.module.ts&#039;\n   },\n\n   shared: {\n     ...shareAll({ singleton: true, strictVersion: true, requiredVersion: &#039;auto&#039; }),\n   },\n\n });<\/code><\/pre>\n<pre><code class=\"language-javascript\">\/\/ projects\/mfe2\/webpack.config.js\n\n const { shareAll, withModuleFederationPlugin } = require(&#039;@angular-architects\/module-federation\/webpack&#039;);\n\n module.exports = withModuleFederationPlugin({\n\n   name: &#039;mfe2&#039;,\n\n   exposes: {\n     \/\/ Adjusted line:\n     &#039;.\/Module&#039;: &#039;.\/projects\/mfe2\/src\/app\/bookings\/bookings.module.ts&#039;\n   },\n\n   shared: {\n     ...shareAll({ singleton: true, strictVersion: true, requiredVersion: &#039;auto&#039; }),\n   },\n\n });<\/code><\/pre>\n<h3>Trying it Out<\/h3>\n<p>For each route loading a Micro Frontend, the shell's <code><code>AppComponent<\/code><code> contains a <\/code><code>routerLink<\/code><\/code>:<\/p>\n<pre><code class=\"language-html\">&lt;!-- projects\/shell\/src\/app\/app.component.html --&gt;\n &lt;ul&gt;\n     &lt;li&gt;&lt;img src=&quot;..\/assets\/angular.png&quot; width=&quot;50&quot;&gt;&lt;\/li&gt;\n     &lt;li&gt;&lt;a routerLink=&quot;\/&quot;&gt;Home&lt;\/a&gt;&lt;\/li&gt;\n     &lt;li&gt;&lt;a routerLink=&quot;\/flights&quot;&gt;Flights&lt;\/a&gt;&lt;\/li&gt;\n     &lt;li&gt;&lt;a routerLink=&quot;\/bookings&quot;&gt;Bookings&lt;\/a&gt;&lt;\/li&gt;\n &lt;\/ul&gt;\n\n &lt;router-outlet&gt;&lt;\/router-outlet&gt;<\/code><\/pre>\n<p>That's it. Just start all the three projects (e. g. by using <code><code>npm run run:all<\/code><\/code>). The main difference to the result in the previous article is that now the shell informs itself about the Micro Frontends at runtime. If you want to point the shell to different Micro Frontends, just adjust the manifest.<\/p>\n<h2>Going &quot;Dynamic Dynamic&quot;<\/h2>\n<p>The solution we have so far is suitable in many situations: The usage of the manifest allows to adjust it to different environments without rebuilding the application. Also, if we switch out the manifest for a dynamic REST service, we could implement strategies like A\/B testing.<\/p>\n<p>However, in some situation you might not even know about the number of Micro Frontends upfront. This is what we discuss here.<\/p>\n<h3>Adding Custom Metadata to The Manifest<\/h3>\n<p>For dynamically setting up the routes, we need some additional metadata. For this, you might want to extend the manifest:<\/p>\n<pre><code class=\"language-json\">{\n     &quot;mfe1&quot;: {\n         &quot;remoteEntry&quot;: &quot;http:\/\/localhost:4201\/remoteEntry.js&quot;,\n\n         &quot;exposedModule&quot;: &quot;.\/Module&quot;,\n         &quot;displayName&quot;: &quot;Flights&quot;,\n         &quot;routePath&quot;: &quot;flights&quot;,\n         &quot;ngModuleName&quot;: &quot;FlightsModule&quot;\n     },\n     &quot;mfe2&quot;: {\n         &quot;remoteEntry&quot;: &quot;http:\/\/localhost:4202\/remoteEntry.js&quot;,\n\n         &quot;exposedModule&quot;: &quot;.\/Module&quot;,\n         &quot;displayName&quot;: &quot;Bookings&quot;,\n         &quot;routePath&quot;: &quot;bookings&quot;,\n         &quot;ngModuleName&quot;: &quot;BookingsModule&quot;\n     }\n }<\/code><\/pre>\n<p>Besides <code><code>remoteEntry<\/code><\/code>, all other properties are <strong>custom<\/strong>. <\/p>\n<h3>Types for Custom Configuration<\/h3>\n<p>To represent our extended configuration, we need some types in the shell's code:<\/p>\n<pre><code class=\"language-typescript\">\/\/ projects\/shell\/src\/app\/utils\/config.ts\n\n import { Manifest, RemoteConfig } from &quot;@angular-architects\/module-federation&quot;;\n\n export type CustomRemoteConfig = RemoteConfig &amp; {\n     exposedModule: string;\n     displayName: string;\n     routePath: string;\n     ngModuleName: string;\n };\n\n export type CustomManifest = Manifest&lt;CustomRemoteConfig&gt;;<\/code><\/pre>\n<p>The <code><code>CustomRemoteConfig<\/code><code> type represents the entries in the manifest and the <\/code><code>CustomManifest<\/code><\/code> type the whole manifest.<\/p>\n<h3>Dynamically Creating Routes<\/h3>\n<p>Now, we need an utility function iterating through the whole manifest and creating a route for each Micro Frontend described there:<\/p>\n<pre><code class=\"language-typescript\">\/\/ projects\/shell\/src\/app\/utils\/routes.ts\n\n import { loadRemoteModule } from &#039;@angular-architects\/module-federation&#039;;\n import { Routes } from &#039;@angular\/router&#039;;\n import { APP_ROUTES } from &#039;..\/app.routes&#039;;\n import { CustomManifest } from &#039;.\/config&#039;;\n\n export function buildRoutes(options: CustomManifest): Routes {\n\n     const lazyRoutes: Routes = Object.keys(options).map(key =&gt; {\n         const entry = options[key];\n         return {\n             path: entry.routePath,\n             loadChildren: () =&gt; \n                 loadRemoteModule({\n                     type: &#039;manifest&#039;,\n                     remoteName: key,\n                     exposedModule: entry.exposedModule\n                 })\n                 .then(m =&gt; m[entry.ngModuleName])\n         }\n     });\n\n     return [...APP_ROUTES, ...lazyRoutes];\n }<\/code><\/pre>\n<p>This gives us the same structure, we directly configured above. <\/p>\n<p>The shell's <code><code>AppComponent<\/code><\/code> glues everything together:<\/p>\n<pre><code class=\"language-typescript\">@Component({\n   selector: &#039;app-root&#039;,\n   templateUrl: &#039;.\/app.component.html&#039;\n })\n export class AppComponent implements OnInit  {\n\n   remotes: CustomRemoteConfig[] = [];\n\n   constructor(\n     private router: Router) {\n   }\n\n   async ngOnInit(): Promise&lt;void&gt; {\n     const manifest = getManifest&lt;CustomManifest&gt;();\n\n     \/\/ Hint: Move this to an APP_INITIALIZER \n     \/\/  to avoid issues with deep linking\n     const routes = buildRoutes(manifest);\n     this.router.resetConfig(routes);\n\n     this.remotes = Object.values(manifest);\n   }\n }<\/code><\/pre>\n<p>The <code><code>ngOnInit<\/code><code> method retrieves the loaded manifest (it&#039;s still loaded in the <\/code><code>main.ts<\/code><code> as shown above) and passes it to <\/code><code>buildRoutes<\/code><code>. The retrieved dynamic routes are passed to the router. Also, the values of the key\/value pairs in the manifest, are put into the <\/code><code>remotes<\/code><\/code> field. It's used in the template to dynamically create the menu items:<\/p>\n<pre><code class=\"language-html\">&lt;!-- projects\/shell\/src\/app\/app.component.html --&gt;\n\n &lt;ul&gt;\n     &lt;li&gt;&lt;img src=&quot;..\/assets\/angular.png&quot; width=&quot;50&quot;&gt;&lt;\/li&gt;\n     &lt;li&gt;&lt;a routerLink=&quot;\/&quot;&gt;Home&lt;\/a&gt;&lt;\/li&gt;\n\n     &lt;!-- Dynamically create menu items for all Micro Frontends --&gt;\n     &lt;li *ngFor=&quot;let remote of remotes&quot;&gt;&lt;a [routerLink]=&quot;remote.routePath&quot;&gt;{{remote.displayName}}&lt;\/a&gt;&lt;\/li&gt;\n\n     &lt;li&gt;&lt;a routerLink=&quot;\/config&quot;&gt;Config&lt;\/a&gt;&lt;\/li&gt;\n &lt;\/ul&gt;\n\n &lt;router-outlet&gt;&lt;\/router-outlet&gt;<\/code><\/pre>\n<h3>Trying it Out<\/h3>\n<p>Now, let's try out this &quot;dynamic dynamic&quot; solution by starting the shell and the Micro Frontends (e. g. with <code><code>npm run run:all<\/code><\/code>). <\/p>\n<h2>Some More Details<\/h2>\n<p>So far, we used the high-level functions provided by the plugin. However, for cases you need more control, there are also some low-level alternatives:<\/p>\n<ul>\n<li>\n<p><code><code>loadManifest(...)<\/code><code>: The above used <\/code><code>loadManifest<\/code><code> function provides a second parameter called <\/code><code>skipRemoteEntries<\/code><code>. Set it to <\/code><code>true<\/code><\/code> to prevent loading the entry points. In this case, only the manifest is loaded:<\/p>\n<pre><code class=\"language-typescript\">loadManifest(\"\/assets\/mf.manifest.json\", true)\n     .catch(...)\n     .then(...)\n     .catch(...)<\/code><\/pre>\n<\/li>\n<li>\n<p><code><code>setManifest(...)<\/code><\/code>: This function allows to directly set the manifest. It comes in handy if you load the data from somewhere else. <\/p>\n<\/li>\n<li>\n<p><code><code>loadRemoteEntry(...)<\/code><\/code>: This function allows to directly load the remote entry point. It's useful if you don't use the manifest:<\/p>\n<pre><code class=\"language-typescript\">Promise.all([\n     loadRemoteEntry({ type: 'module', remoteEntry: 'http:\/\/localhost:4201\/remoteEntry.js' }),\n     loadRemoteEntry({ type: 'module', remoteEntry: 'http:\/\/localhost:4202\/remoteEntry.js' })\n ])\n .catch(err => console.error(err))\n .then(_ => import('.\/bootstrap'))\n .catch(err => console.error(err));<\/code><\/pre>\n<\/li>\n<li>\n<p><code><code>loadRemoteModule(...)<\/code><code>: Also, if you don&#039;t want to use the manifest, you can directly load a Micro Frontend with <\/code><code>loadRemoteModule<\/code><\/code>:<\/p>\n<pre><code class=\"language-typescript\">{\n     path: 'flights',\n     loadChildren: () =>\n         loadRemoteModule({\n             type: 'module',\n             remoteEntry: 'http:\/\/localhost:4201\/remoteEntry.js',\n             exposedModule: '.\/Module',\n         }).then((m) => m.FlightsModule),\n },<\/code><\/pre>\n<\/li>\n<\/ul>\n<p>In general I think most people will use the manifest in the future. Even if one doesn't want to load it from a JSON file with <code><code>loadManifest<\/code><code>, one can define it via <\/code><code>setManifest<\/code><\/code>.<\/p>\n<p>The property <code><code>type: &#039;module&#039;<\/code><code> defines that you want to load a &quot;real&quot; EcmaScript module instead of &quot;just&quot; a JavaScript file. This is needed since Angular CLI 13. If you load stuff not built by CLI 13 or higher, you very likely have to set this property to <\/code><code>script<\/code><\/code>. This can also happen via the manifest:<\/p>\n<pre><code class=\"language-json\">{\n     &quot;non-cli-13-stuff&quot;: {\n         &quot;type&quot;: &quot;script&quot;,\n         &quot;remoteEntry&quot;: &quot;http:\/\/localhost:4201\/remoteEntry.js&quot;\n     }\n }<\/code><\/pre>\n<blockquote>\n<p>If an entry in the manifest does not contain a <code><code>type<\/code><code> property, the plugin assumes the value <\/code><code>module<\/code><\/code>. <\/p>\n<\/blockquote>\n<h2>What's next? More on Architecture!<\/h2>\n<p>So far, we've seen that Module Federation is a straightforward solution for creating Micro Frontends on top of Angular. However, when dealing with it, several additional questions come in mind:<\/p>\n<ul>\n<li>According to which criteria can we sub-divide a huge application into micro frontends?<\/li>\n<li>Which access restrictions make sense?<\/li>\n<li>Which proven patterns should we use?<\/li>\n<li>How can we avoid pitfalls when working with Module Federation?<\/li>\n<li>Which advanced scenarios are possible?<\/li>\n<\/ul>\n<p>Our free eBook (about 100 pages) covers all these questions and more:<\/p>\n<p><a href=\"https:\/\/www.angulararchitects.io\/book\"><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/12\/cover-small.png\" alt=\"free ebook\"><\/a><\/p>\n<p>Feel free to <a href=\"https:\/\/www.angulararchitects.io\/book\">download it here<\/a> now!<\/p>\n<h2>Conclusion<\/h2>\n<p>Dynamic Module Federation provides more flexibility as it allows loading Micro Frontends we don't have to know at compile time. We don't even have to know their number upfront. This is possible because of the runtime API provided by webpack. To make using it a bit easier, the <code>@angular-architects\/module-federation<\/code> plugin wrap it nicely into some convenience functions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Loading microfrontends not known at compile time.<\/p>\n","protected":false},"author":9,"featured_media":4183,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":""},"categories":[],"tags":[],"class_list":["post-4186","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","post_series-module-federation"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Dynamic Module Federation with Angular - ANGULARarchitects<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Dynamic Module Federation with Angular - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"Loading microfrontends not known at compile time.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2020-06-26T22:06:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-01-19T14:11:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1159\" \/>\n\t<meta property=\"og:image:height\" content=\"645\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Manfred Steyer, GDE\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@daniel\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manfred Steyer, GDE\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Dynamic Module Federation with Angular\",\"datePublished\":\"2020-06-26T22:06:12+00:00\",\"dateModified\":\"2024-01-19T14:11:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/\"},\"wordCount\":1004,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png\",\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/\",\"name\":\"Dynamic Module Federation with Angular - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png\",\"datePublished\":\"2020-06-26T22:06:12+00:00\",\"dateModified\":\"2024-01-19T14:11:42+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png\",\"width\":1159,\"height\":645},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Dynamic Module Federation with Angular\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"name\":\"ANGULARarchitects\",\"description\":\"AngularArchitects.io\",\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\",\"name\":\"ANGULARarchitects\",\"alternateName\":\"SOFTWAREarchitects\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"width\":644,\"height\":216,\"caption\":\"ANGULARarchitects\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/github.com\/angular-architects\",\"https:\/\/www.linkedin.com\/company\/angular-architects\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\",\"name\":\"Manfred Steyer, GDE\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"caption\":\"Manfred Steyer, GDE\"},\"sameAs\":[\"https:\/\/x.com\/daniel\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Dynamic Module Federation with Angular - ANGULARarchitects","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/","og_locale":"en_US","og_type":"article","og_title":"Dynamic Module Federation with Angular - ANGULARarchitects","og_description":"Loading microfrontends not known at compile time.","og_url":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/","og_site_name":"ANGULARarchitects","article_published_time":"2020-06-26T22:06:12+00:00","article_modified_time":"2024-01-19T14:11:42+00:00","og_image":[{"width":1159,"height":645,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png","type":"image\/png"}],"author":"Manfred Steyer, GDE","twitter_card":"summary_large_image","twitter_creator":"@daniel","twitter_misc":{"Written by":"Manfred Steyer, GDE","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Dynamic Module Federation with Angular","datePublished":"2020-06-26T22:06:12+00:00","dateModified":"2024-01-19T14:11:42+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/"},"wordCount":1004,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png","inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/","url":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/","name":"Dynamic Module Federation with Angular - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png","datePublished":"2020-06-26T22:06:12+00:00","dateModified":"2024-01-19T14:11:42+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/06\/overview.png","width":1159,"height":645},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Dynamic Module Federation with Angular"}]},{"@type":"WebSite","@id":"https:\/\/www.angulararchitects.io\/en\/#website","url":"https:\/\/www.angulararchitects.io\/en\/","name":"ANGULARarchitects","description":"AngularArchitects.io","publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.angulararchitects.io\/en\/#organization","name":"ANGULARarchitects","alternateName":"SOFTWAREarchitects","url":"https:\/\/www.angulararchitects.io\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","width":644,"height":216,"caption":"ANGULARarchitects"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/github.com\/angular-architects","https:\/\/www.linkedin.com\/company\/angular-architects\/"]},{"@type":"Person","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951","name":"Manfred Steyer, GDE","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","caption":"Manfred Steyer, GDE"},"sameAs":["https:\/\/x.com\/daniel"]}]}},"_links":{"self":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/4186","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/comments?post=4186"}],"version-history":[{"count":1,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/4186\/revisions"}],"predecessor-version":[{"id":24241,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/4186\/revisions\/24241"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/4183"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=4186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=4186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=4186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}