{"id":4296,"date":"2020-09-06T23:13:47","date_gmt":"2020-09-06T21:13:47","guid":{"rendered":"https:\/\/angulararchitects.io\/?p=4296"},"modified":"2024-01-19T15:06:16","modified_gmt":"2024-01-19T14:06:16","slug":"dynamic-module-federation-with-angular-2","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/","title":{"rendered":"Building A Plugin-based Workflow Designer With Angular and Module Federation"},"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-federation6a0131d52ed22\" 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-federation6a0131d52ed22\"\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 4 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><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular\/\">Dynamic Module Federation with Angular<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><span class=\"wp-post-series-box__current\">Building A Plugin-based Workflow Designer With Angular and Module Federation<\/span><\/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<p>In the <a href=\"https:\/\/www.angulararchitects.io\/aktuelles\/dynamic-module-federation-with-angular\/\">previous article of this series<\/a>, I showed how to use Dynamic Module Federation. This allows us to load Micro Frontends -- or remotes, which is the more general term in Module Federation -- not known at compile time. We don't even need to know the number of remotes upfront.<\/p>\n<p>While the previous article leveraged the router for integrating remotes available, this article shows how to load individual components. The example used for this is a simple plugin-based workflow designer.<\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2020\/09\/result.png\" alt=\"The Workflow Designer can load separately compiled and deployed tasks\" \/><\/p>\n<p>The workflow designer acts as a so-called host loading tasks from plugins provided as remotes. Thus, they can be compiled and deployed individually. After starting the workflow designer, it gets a configuration describing the available plugins: <\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2020\/09\/config.png\" alt=\"The configuration informs about where to find the tasks\" \/><\/p>\n<p>Please note that these plugins are provided via different origins (<a href=\"http:\/\/localhost:4201\">http:\/\/localhost:4201<\/a> and <a href=\"http:\/\/localhost:4202\">http:\/\/localhost:4202<\/a>), and the workflow designer is served from an origin of its own (<a href=\"http:\/\/localhost:4200\">http:\/\/localhost:4200<\/a>).<\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/manfredsteyer\/module-federation-with-angular-dynamic-workflow-designer\">Source Code<\/a><\/p>\n<blockquote>\n<p>Thanks to <a href=\"https:\/\/twitter.com\/ScriptedAlchemy\">Zack Jackson<\/a> and <a href=\"https:\/\/twitter.com\/jherr\">Jack Herrington<\/a>, who helped me to understand the rater new API for Dynamic Module Federation.<\/p>\n<\/blockquote>\n<p><strong>Important<\/strong>: This article is written for Angular and <strong>Angular CLI 14.x<\/strong> and above. Make sure you have a fitting version if you try out the examples outlined here! For more details on the differences\/ migration to Angular 14.x please see this <a href=\"https:\/\/github.com\/angular-architects\/module-federation-plugin\/blob\/main\/migration-guide.md\">migration guide<\/a>.<\/p>\n<h2>Building the Plugins<\/h2>\n<p>The plugins are provided via separate Angular applications. For the sake of simplicity, all applications are part of the same monorepo. Their webpack configuration uses Module Federation for exposing the individual plugins as shown in the previous articles of this series:<\/p>\n<pre><code class=\"language-javascript\">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     &#039;.\/Download&#039;: &#039;.\/projects\/mfe1\/src\/app\/download.component.ts&#039;,\n     &#039;.\/Upload&#039;: &#039;.\/projects\/mfe1\/src\/app\/upload.component.ts&#039;\n   },\n\n   shared: {\n     ...shareAll({ singleton: true, strictVersion: true, requiredVersion: &#039;auto&#039; }),\n   },\n\n });<\/code><\/pre>\n<p>One difference to the configurations shown in the previous articles is that here we are directly exposing standalone components. Each component represents a task that can be put into the workflow.   <\/p>\n<p>The combination of <code>singleton: true<\/code> and <code>strictVersion: true<\/code> makes webpack emit a runtime error when the shell and the micro frontend(s) need different incompatible versions (e. g. two different major versions). If we skipped <code>strictVersion<\/code> or set it to <code>false<\/code>, webpack would only emit a warning at runtime.<\/p>\n<h2>Loading the Plugins into the Workflow Designer<\/h2>\n<p>For loading the plugins into the workflow designer, I'm using the helper function <code>loadRemoteModule<\/code> provided by the @angular-architects\/module-federation plugin. To load the above mentioned <code>Download<\/code> task, <code>loadRemoteModule<\/code> can be called this way:<\/p>\n<pre><code class=\"language-typescript\">import { loadRemoteModule } from &#039;@angular-architects\/module-federation&#039;;\n\n [...]\n\n const component = await loadRemoteModule({\n     type: &#039;module&#039;,\n     remoteEntry: &#039;http:\/\/localhost:4201\/remoteEntry.js&#039;,\n     exposedModule: &#039;.\/Download&#039;\n })<\/code><\/pre>\n<h2>Providing Metadata on the Plugins<\/h2>\n<p>At runtime, we need to provide the workflow designer with key data about the plugins. The type used for this is called <code>PluginOptions<\/code> and extends the <code>LoadRemoteModuleOptions<\/code> shown in the previous section by a <code>displayName<\/code> and a <code>componentName<\/code>:<\/p>\n<pre><code class=\"language-typescript\">export type PluginOptions = LoadRemoteModuleOptions &amp; {\n     displayName: string;\n     componentName: string;\n };<\/code><\/pre>\n<blockquote>\n<p>An alternative to this is extending the Module Federation Manifest as shown in the <a href=\"https:\/\/www.angulararchitects.io\/aktuelles\/dynamic-module-federation-with-angular\/\">previous article on Dynamic Module Federation<\/a>.<\/p>\n<\/blockquote>\n<p>While the <code>displayName<\/code> is the name presented to the user, the <code>componentName<\/code> refers to the TypeScript class representing the Angular component in question.<\/p>\n<p>For loading this key data, the workflow designer leverages a <code>LookupService<\/code>:<\/p>\n<pre><code class=\"language-typescript\">@Injectable({ providedIn: &#039;root&#039; })\n export class LookupService {\n     lookup(): Promise&lt;PluginOptions[]&gt; {\n         return Promise.resolve([\n             {\n                 type: &#039;module&#039;,\n                 remoteEntry: &#039;http:\/\/localhost:4201\/remoteEntry.js&#039;,\n                 exposedModule: &#039;.\/Download&#039;,\n\n                 displayName: &#039;Download&#039;,\n                 componentName: &#039;DownloadComponent&#039;\n             },\n             [...]\n         ] as PluginOptions[]);\n     }\n }<\/code><\/pre>\n<p>For the sake of simplicity, the <code>LookupService<\/code> provides some hardcoded entries. In the real world, it would very likely request this data from a respective HTTP endpoint.<\/p>\n<h2>Dynamically Creating the Plugin Component<\/h2>\n<p>The workflow designer represents the plugins with a <code>PluginProxyComponent<\/code>. It takes a <code>PluginOptions<\/code> object via an input, loads the described plugin via Dynamic Module Federation and displays the plugin's component within a placeholder:<\/p>\n<pre><code class=\"language-typescript\">@Component({\n     standalone: true,\n     selector: &#039;plugin-proxy&#039;,\n     template: `\n         &lt;ng-container #placeHolder&gt;&lt;\/ng-container&gt;\n     `\n })\n export class PluginProxyComponent implements OnChanges {\n     @ViewChild(&#039;placeHolder&#039;, { read: ViewContainerRef, static: true })\n     viewContainer: ViewContainerRef;\n\n     constructor() { }\n\n     @Input() options: PluginOptions;\n\n     async ngOnChanges() {\n         this.viewContainer.clear();\n\n         const Component = await loadRemoteModule(this.options)\n             .then(m =&gt; m[this.options.componentName]);\n\n         this.viewContainer.createComponent(Component);\n     }\n }<\/code><\/pre>\n<p>In versions before Angular 13, we needed to use a ComponentFactoryResolver to get the loaded component's factory:<\/p>\n<pre><code class=\"language-typescript\">\/\/ Before Angular 13, we needed to retrieve a ComponentFactory\n \/\/\n \/\/ export class PluginProxyComponent implements OnChanges {\n \/\/     @ViewChild(&#039;placeHolder&#039;, { read: ViewContainerRef, static: true })\n \/\/     viewContainer: ViewContainerRef;\n\n \/\/     constructor(\n \/\/       private injector: Injector,\n \/\/       private cfr: ComponentFactoryResolver) { }\n\n \/\/     @Input() options: PluginOptions;\n\n \/\/     async ngOnChanges() {\n \/\/         this.viewContainer.clear();\n\n \/\/         const component = await loadRemoteModule(this.options)\n \/\/             .then(m =&gt; m[this.options.componentName]);\n\n \/\/         const factory = this.cfr.resolveComponentFactory(component);\n\n \/\/         this.viewContainer.createComponent(factory, null, this.injector);\n \/\/     }\n \/\/ }<\/code><\/pre>\n<h2>Wiring Up Everything<\/h2>\n<p>Now, it's time to wire up the parts mentioned above. For this, the workflow designer's <code>AppComponent<\/code> gets a <code>plugins<\/code> and a <code>workflow<\/code> array. The first one represents the <code>PluginOptions<\/code> of the available plugins and thus all available tasks while the second one describes the <code>PluginOptions<\/code> of the selected tasks in the configured sequence:<\/p>\n<pre><code class=\"language-typescript\">@Component({ [...] })\n export class AppComponent implements OnInit {\n\n   plugins: PluginOptions[] = [];\n   workflow: PluginOptions[] = [];\n   showConfig = false;\n\n   constructor(\n     private lookupService: LookupService) {\n   }\n\n   async ngOnInit(): Promise&lt;void&gt; {\n     this.plugins = await this.lookupService.lookup();\n   }\n\n   add(plugin: PluginOptions): void {\n     this.workflow.push(plugin);\n   }\n\n   toggle(): void {\n     this.showConfig = !this.showConfig;\n   }\n }<\/code><\/pre>\n<p>The <code>AppComponent<\/code> uses the injected <code>LookupService<\/code> for populating its <code>plugins<\/code> array. When a plugin is added to the workflow, the <code>add<\/code> method puts its <code>PluginOptions<\/code> object into the workflow array.<\/p>\n<p>For displaying the workflow, the designer just iterates all items in the workflow array and creates a <code>plugin-proxy<\/code> for them:<\/p>\n<pre><code class=\"language-html\">&lt;ng-container *ngFor=&quot;let p of workflow; let last = last&quot;&gt;\n     &lt;plugin-proxy [options]=&quot;p&quot;&gt;&lt;\/plugin-proxy&gt;\n     &lt;i *ngIf=&quot;!last&quot; class=&quot;arrow right&quot; style=&quot;&quot;&gt;&lt;\/i&gt;\n &lt;\/ng-container&gt; <\/code><\/pre>\n<p>As discussed above, the proxy loads the plugin (at least, if it isn't already loaded) and displays it.<\/p>\n<p>Also, for rendering the toolbox displayed on the left, it goes through all entries in the <code>plugins<\/code> array. For each of them it displays a hyperlink calling bound to the <code>add<\/code> method:<\/p>\n<pre><code class=\"language-html\">&lt;div class=&quot;vertical-menu&quot;&gt;\n     &lt;a href=&quot;#&quot; class=&quot;active&quot;&gt;Tasks&lt;\/a&gt;\n     &lt;a *ngFor=&quot;let p of plugins&quot; (click)=&quot;add(p)&quot;&gt;Add {{p.displayName}}&lt;\/a&gt;\n &lt;\/div&gt;<\/code><\/pre>\n<h2>Conclusion<\/h2>\n<p>While Module Federation comes in handy for implementing Micro Frontends, it can also be used for setting up plugin architectures. This allows us to extend an existing solution by 3rd parties. It also seems to be a good fit for SaaS applications, which needs to be adapted to different customers' needs.  <\/p>\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<article>\n","protected":false},"excerpt":{"rendered":"<p>Module Federation allows loading plugins from other origins,<\/p>\n","protected":false},"author":9,"featured_media":4280,"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-4296","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>Building A Plugin-based Workflow Designer With Angular and Module Federation - 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-2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building A Plugin-based Workflow Designer With Angular and Module Federation - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"Module Federation allows loading plugins from other origins,\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2020-09-06T21:13:47+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-01-19T14:06:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1999\" \/>\n\t<meta property=\"og:image:height\" content=\"714\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\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=\"6 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-2\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Building A Plugin-based Workflow Designer With Angular and Module Federation\",\"datePublished\":\"2020-09-06T21:13:47+00:00\",\"dateModified\":\"2024-01-19T14:06:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/\"},\"wordCount\":840,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg\",\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/\",\"name\":\"Building A Plugin-based Workflow Designer With Angular and Module Federation - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg\",\"datePublished\":\"2020-09-06T21:13:47+00:00\",\"dateModified\":\"2024-01-19T14:06:16+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg\",\"width\":1999,\"height\":714},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building A Plugin-based Workflow Designer With Angular and Module Federation\"}]},{\"@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":"Building A Plugin-based Workflow Designer With Angular and Module Federation - 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-2\/","og_locale":"en_US","og_type":"article","og_title":"Building A Plugin-based Workflow Designer With Angular and Module Federation - ANGULARarchitects","og_description":"Module Federation allows loading plugins from other origins,","og_url":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/","og_site_name":"ANGULARarchitects","article_published_time":"2020-09-06T21:13:47+00:00","article_modified_time":"2024-01-19T14:06:16+00:00","og_image":[{"width":1999,"height":714,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg","type":"image\/jpeg"}],"author":"Manfred Steyer, GDE","twitter_card":"summary_large_image","twitter_creator":"@daniel","twitter_misc":{"Written by":"Manfred Steyer, GDE","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Building A Plugin-based Workflow Designer With Angular and Module Federation","datePublished":"2020-09-06T21:13:47+00:00","dateModified":"2024-01-19T14:06:16+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/"},"wordCount":840,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg","inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/dynamic-module-federation-with-angular-2\/","url":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/","name":"Building A Plugin-based Workflow Designer With Angular and Module Federation - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg","datePublished":"2020-09-06T21:13:47+00:00","dateModified":"2024-01-19T14:06:16+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/09\/shutterstock-1176723403.jpg","width":1999,"height":714},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/dynamic-module-federation-with-angular-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Building A Plugin-based Workflow Designer With Angular and Module Federation"}]},{"@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\/4296","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=4296"}],"version-history":[{"count":1,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/4296\/revisions"}],"predecessor-version":[{"id":24237,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/4296\/revisions\/24237"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/4280"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=4296"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=4296"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=4296"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}