<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/filip-voska/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Thu, 16 Apr 2026 15:26:52 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>41704https://infinum.com/uploads/2023/08/Micro_Frontends_part-2-hero-min.webp</url>
				</image>
				<title>Implementing Micro Frontends – What to Look Out For</title>
				<link>https://infinum.com/blog/micro-frontends-implementation-challenges/</link>
				<pubDate>Wed, 30 Aug 2023 10:23:00 +0000</pubDate>
				<dc:creator>Filip Voska</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=41704</guid>
				<description>
					<![CDATA[<p>We uncover some challenges that come with implementing Micro Frontends architecture, and propose solutions for addressing them. </p>
<p>The post <a href="https://infinum.com/blog/micro-frontends-implementation-challenges/">Implementing Micro Frontends – What to Look Out For</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-251"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-36-text js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	<strong>In the second chapter of our Micro Frontends story, we look at some challenges of implementing MFE architecture and propose solutions for addressing them. </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	In our previous article, <a href="https://infinum.com/blog/micro-frontends-nx-angular/" target="_blank" rel="noreferrer noopener">Scale Smarter with Micro Frontends using Nx and Angular</a>, we talked about what Micro Frontends are and what problems they solve. As a quick reminder, there’s an <a href="https://github.com/infinum/js-infinum-talks-mfe-demo" target="_blank" rel="noreferrer noopener">example application repository</a> and a <a href="https://www.youtube.com/watch?v=GNj4OjKTK8Q" target="_blank" rel="noreferrer noopener">video presentation</a> accompanying the article. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-100'
	>
	In this follow-up, we’ll uncover some oddities and talk about certain obstacles that you might come across while implementing a Micro Frontends architecture.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-102">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-103'
	>
	Micro details of Micro Frontends</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-105">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-106'
	>
	Even if you use Nx to make working with a monorepo with MFEs easier, there are still many details you will have to figure out on your own. To give you some idea of the challenges you might face, we will go over some of the potential hurdles and propose solutions for overcoming them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-108">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-109'
	>
	Initialization logic for each individual Micro Frontends app</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-111">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-112'
	>
	<strong>The challenge</strong></h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-116"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-114">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-115'
	>
	Specific to Angular applications, you can use <a href="https://angular.io/api/core/APP_INITIALIZER" target="_blank" rel="noreferrer noopener">APP_INITIALIZER</a> to write code that should be executed during app initialization (commonly called <a href="https://angular.io/guide/standalone-components#bootstrapping-an-application-using-a-standalone-component" target="_blank" rel="noreferrer noopener">bootstrapping</a>), be it synchronous or asynchronous. Angular will wait for all APP_INITIALIZERs to resolve before starting the app. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-119"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-117">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-118'
	>
	This is most commonly used to set up some configuration or fetch some data that should be immediately available for the whole application during start-up. Common use cases are checking whether the app should be loaded in maintenance mode or checking if the user is logged in.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-122"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-120">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-121'
	>
	With regular monoliths, there is a single place where you can put all initialization logic – a single entry module or component. With MFEs, that is no longer the case. The host application is started only once, and child applications are loaded as if you were doing regular module lazy-loading.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-125"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-123">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-124'
	>
	If an MFE child application needs to run an initialization logic when it loads, you cannot use APP_INITIALIZER as you would in the host application. You have to find a custom solution.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-128"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-126">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-127'
	>
	<strong>Our solution</strong></h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-131"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-129">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-130'
	>
	Luckily, Angular’s robust routing features provide <a href="https://angular.io/guide/router#preventing-unauthorized-access" target="_blank" rel="noreferrer noopener">guards</a> that allow us to execute code during certain <a href="https://angular.io/guide/router-reference#router-events" target="_blank" rel="noreferrer noopener">router events</a>. Guards are most commonly used to prevent navigation to a certain route. There is one guard in particular that is of interest to us: <a href="https://angular.io/api/router/CanLoad" target="_blank" rel="noreferrer noopener">CanLo</a>ad. This guard will execute only once, during route loading. If the guard passes, the route gets loaded; if not, navigation is canceled, and the target route code does not load.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-134"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-132">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-133'
	>
	Because MFE child applications load under specific routes, we can place a CanLoad guard on an MFE app’s main route, on which the remote entry gets loaded.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-137"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-135">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-136'
	>
	CanLoad guard can be combined with an extension of <a href="https://angular.io/api/core/ApplicationInitStatus" target="_blank" rel="noreferrer noopener">ApplicationInitStatus</a> that is used by APP_INITIALIZER itself. This allows you to create something custom that behaves in a similar way to APP_INITIALIZER. Sadly, these parts of Angular are not that well documented, so you will have to go digging into <a href="https://github.com/angular/angular/blob/c1052cf7a77e0bf2a4ec14f9dd5abc92034cfd2e/packages/core/src/application_init.ts#L108" target="_blank" rel="noreferrer noopener">the source code</a> to figure out how to wire everything together. It is also possible that these internals might change a bit in future versions of Angular.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-140"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-138">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-139'
	>
	We won’t go into further detail here, but playing around with all this will allow you to create something very similar to the APP_INITIALIZER for your MFE apps’ entry modules. You could perhaps call it MODULE_INITIALIZER and use it like this in your child app’s remote entry:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-142"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-javascript github-light" data-language="javascript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">@</span><span class="token" style="color: #6f42c1;">NgModule</span><span class="token">(</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">providers</span><span class="token">:</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">provide</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">MODULE_INITIALIZER</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #6f42c1;">useFactory</span><span class="token">:</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #e36209;">auth</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">AuthService</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> initialization logic</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">deps</span><span class="token">:</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #24292e;">AuthService</span><span class="token">]</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">multi</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">export</span><span class="token"> </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">RemoteEntryModule</span><span class="token"> </span><span class="token">{</span><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-145"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-143">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-144'
	>
	Environment-specific configurations</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-148"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-146">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-147'
	>
	<strong>The challenge</strong></h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-151"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-149">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-150'
	>
	Most apps need some environment-specific configuration for things like API URLs, logging, and so on. Some configurations might be shared between all apps, while some configurations will be app-specific.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-154"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-152">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-153'
	>
	Many Angular developers use Angular’s so-called environment files and have separate configuration files for each target environment. We think this is a bad idea, and you can find out why in our documentation pages for our <a href="https://infinum.github.io/ngx-nuts-and-bolts/" target="_blank" rel="noreferrer noopener">ngx-nuts-and-bolts library</a>, and, more specifically, in the docs for <a href="https://infinum.github.io/ngx-nuts-and-bolts/docs/environment-variables">EnvironmentVariablesService</a>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-157"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-155">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-156'
	>
	In short, our proposed solution for classic SPAs is to source environment configuration at run-time, instead of build-time. This can be done by fetching the config.json file from assets. Values in this config.json file can be replaced in a post-build and pre-deploy step in your deployment pipeline.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-160"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-158">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-159'
	>
	<strong>Our solution</strong></h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-163"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-161">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-162'
	>
	What we describe in our ngx-nuts-and-bolts docs can 100% be applied for the host MFE app. There is just one small tweak you have to make in order to make it work with child MFE apps. Each MFE app should have its own config.json, and when the remote entry module gets loaded, it should be fetched, and the child MFE app should get its own instance of EnvironmentVariablesService that will be instantiated with that app’s specific values for environment variables.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-166"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-164">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-165'
	>
	Child MFE apps can still inject the parent app’s EnvironmentVariablesService for shared configuration values, but it can also have its own version (provided you separate out dependency injection (DI) tokens for services).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-169"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-167">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-168'
	>
	Serving and fetching assets</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-172"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-170">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-171'
	>
	<strong>The challenge</strong></h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-173">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-174'
	>
	With MFEs, assets can be served from many different places. Some assets might be shared between all apps, like the company logo or font files. Other assets might only be used by one specific app, like translation files. You have to figure out where to store all these assets and how to serve them. You might opt for centralization, or you might want to keep it app-specific; it will depend on the exact use case you have. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-178"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-176">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-177'
	>
	Keep in mind that you can combine centralized and decentralized approaches. For example, use a centralized approach for shared fonts and logos, and keep app-specific images and other assets decentralized.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-181"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-179">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-180'
	>
	If you go down the centralization route, it’s relatively easy – all apps need to know about the centralized URL from which assets can be fetched. This URL can be provided by the host application as a shared environment variable that is loaded using the mechanism described in the previous section about Environment-specific configurations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-184"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-182">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-183'
	>
	Despite being more complex, it might be worth it to go down the decentralized route, where each app has its own asset files in its own build. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-186"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-185'
	>
	With a decentralized approach, we help individual teams be as independent as possible during deployments – there is no reliance upon an asset being added to a centralized place.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-189"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-187">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-188'
	>
	There is one slight issue, though. All apps are executed from the same root URL, even if various entry modules for child MFE apps are loaded from different URLs. This is one of the main points of MFEs. Assets that are part of a child MFE app’s build artifacts will be served from a different URL, in the same way that the remote entry of a child MFE app gets loaded from a different URL. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-192"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-190">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-191'
	>
	Let’s take a look at an example from our Phlex app that has Movies and Music child apps. If a path to an asset is defined relatively (which it always is in your source code), the path will be resolved relative to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base" target="_blank" rel="noreferrer noopener">base URL</a>. The result is that ./assets/movies-app-logo.svg will always be resolved to phlex.com/assets/movies-app-logo.svg, never to movies.phlex.com/assets/movies-app-logo.svg. If this file is part of the child MFE app’s build artifacts, phlex.com/assets/movies-app-logo.svg will return 404, while movies.phlex.com/assets/movies-app-logo.svg returns 200.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-195"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-193">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-194'
	>
	<strong>Our solution</strong></h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-198"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-196">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-197'
	>
	You need a mechanism that lets the child MFE app’s codebase know how to resolve URLs relative to the child app’s file server. Luckily, the solution is there, almost out of the box. In the same way that we want to know the URL of our child app, Webpack’s Module Federation also needs to know where to load remote entry modules from.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-201"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-199">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-200'
	>
	When everything is set up using Nx, URLs for remote entries for each child MFE app are stored in module-federation.manifest.json in the root app. All you need to do is pass this information down to each child app. You can do this via <a href="https://angular.io/api/router/Route#providers" target="_blank" rel="noreferrer noopener">route providers</a> under a DI token (e.g., MFE_CHILD_APP_URL). Child MFE apps can inject the provided URL via the token and prepend all relative URLs so that they get resolved absolutely. Our previous example with ./assets/movies-app-logo.svg would have to be updated to load the file from &lt;MFE_CHILD_APP_URL&gt;/assets/movies-app-logo.svg. The Movies MFE app would receive movide.phlex.com under MFE_CHILD_APP_URL, so the URL ends up as an absolute URL: movies.phlex.com/assets/movies-app-logo.svg.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-204"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-202">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-203'
	>
	Providing MFE_CHILD_APP_URL to child MFE apps can be done via a router, as in this example:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-206"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-javascript github-light" data-language="javascript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">pa</span><span class="token" style="color: #6f42c1;">t</span><span class="token" style="color: #6f42c1;">h</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">movies</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">provide</span><span class="token" style="color: #6f42c1;">r</span><span class="token" style="color: #6f42c1;">s</span><span class="token">:</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #6f42c1;">provideAppUrl</span><span class="token">(</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">movies</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">)</span><span class="token">]</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">loadChildr</span><span class="token" style="color: #6f42c1;">e</span><span class="token" style="color: #6f42c1;">n</span><span class="token">:</span><span class="token"> </span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">loadRemoteModule</span><span class="token">(</span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">movies</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">./Module</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">then</span><span class="token">(</span><span class="token">(</span><span class="token" style="color: #e36209;">m</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=&gt;</span><span class="token"> </span><span class="token" style="color: #24292e;">m</span><span class="token" style="color: #24292e;">.RemoteEntryModul</span><span class="token">e</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-209"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-207">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-208'
	>
	The <code>provideAppUrl</code> function reads data from module-federation.manifest.json, which itself could look something like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-211"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-javascript github-light" data-language="javascript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">movies</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">: </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">https://movies.phlex.com</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">music</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">: </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">https://music.phlex.com</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-214"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-212">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-213'
	>
	Once the URL is found in this file, the function provides it under the MFE_CHILD_APP_URL DI token, so that it can be injected into the child app’s codebase in order to construct URLs.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-217"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-215">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-216'
	>
	Dependency Injection, Providers, and Interceptors</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-220"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-218">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-219'
	>
	The challenge</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-223"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-221">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-222'
	>
	In Angular, dependency injection is used extensively, and services must be provided somewhere. Sometimes, it can be hard to figure out if a service should be provided by the host application or by the child application. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-226"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-224">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-225'
	>
	There is also the question of whether it should be a global singleton or whether a new instance should be provided for each MFE app. Good patterns for providing services (e.g., functional providers like <a href="https://angular.io/api/common/http/provideHttpClient" target="_blank" rel="noreferrer noopener">provideHttpClient</a>) and good use of things like <a href="https://angular.io/guide/dependency-injection-in-action#make-a-dependency-optional-and-limit-search-with-host" target="_blank" rel="noreferrer noopener">optional injection flags</a> can go a long way in helping you keep track of things and make debugging easier.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-229"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-227">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-228'
	>
	Some things have to be provided globally, like <a href="https://angular.io/api/common/http/HttpInterceptor" target="_blank" rel="noreferrer noopener">HTTP interceptors</a>. Interceptors cannot be controlled by child applications, and they have to be set by the host application. This is a very similar issue to the initialization issue. It’s made a bit harder because there should ideally be only one instance of the HttpClient. Theoretically, each child MFE app could have its own HttpClient, but that would mean that no interceptors can be inherited from the parent app. It’s certainly doable if you have a good way of providing the same interceptors to all child apps, but it is more prone to causing errors, as you have to make sure all apps include all the necessary providers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-232"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-230">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-231'
	>
	Our solution</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-235"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-233">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-234'
	>
	To solve the problem, you must rely on the benefit of MFEs and Module Federation, which allows us to have singletons across the host and all child apps.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-238"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-236">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-237'
	>
	A good solution is to create a service in the host app that is shared as a singleton with all child apps. This service allows child apps to “register” some handlers in a similar way to regular HTTP interceptor definitions, but it’s not done via DI (because interceptors have to be provided at the time HttpClient is provided). The host app will register a single interceptor, but that interceptor’s implementation will execute all the registered child handlers dynamically. There is even an unexpected added benefit of having control of the order of interceptors, something that is a bit more obscure when defining multiple regular individual interceptors.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-241"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-239">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-240'
	>
	The solution integrates with the previously mentioned MODULE_INITIALIZER by implementing a module initializer factory, like so:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-243"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-javascript github-light" data-language="javascript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">export</span><span class="token"> </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token" style="color: #6f42c1;">configFactory</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #e36209;">configService</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ConfigService</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #e36209;">protectedResourceStore</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ProtectedResourceStore</span><span class="token">
</span></span><span class="line"><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=&gt;</span><span class="token"> </span><span class="token" style="color: #d73a49;">async</span><span class="token"> </span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">=&gt;</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">apiUrl</span><span class="token"> </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">await</span><span class="token"> </span><span class="token" style="color: #24292e;">configService</span><span class="token">.</span><span class="token" style="color: #6f42c1;">loadConfig</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #24292e;">protectedResourceStore</span><span class="token">.</span><span class="token" style="color: #6f42c1;">addProtectedResource</span><span class="token">(</span><span class="token" style="color: #24292e;">apiUrl</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-246"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-244">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-245'
	>
	During MFE apps’ module initialization, we will fetch this app’s config.json. The config file includes the apiUrl property, and we can register this URL with ProtectedResourceStore. URLs registered in this store are used by the authentication interceptor in the host application to determine whether an authentication token should be attached or not.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-249"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-247">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-248'
	>
	Managing dependencies</h3></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-254"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-252"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-253">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2023/08/Micro_Frontends-in-article-visual-1-min.webp"
					class="image__img block-media__image-img"
					alt=""
										height="947"
															width="1400"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-323"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-255">
	

</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-256">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-257'
	>
	The challenge</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-261"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-259">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-260'
	>
	Some packages in the monorepo will be used by a large number of other packages and applications. Take extra care when making changes to these packages, as you will have to handle breaking changes in many places. Taking a look at <a href="https://nx.dev/core-features/explore-graph" target="_blank" rel="noreferrer noopener">Nx’s project graph</a> and checking the list of affected packages can help you figure out what is the scope of your changes. When you make the changes to a shared package, make sure to communicate the change to other teams, ideally via email, with a link to the changelog that includes information on how to handle changes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-264"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-262">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-263'
	>
	Changes to third-party packages can be even more cumbersome if they are used by all the apps. If you update Angular to a new major version, you have to handle breaking changes in all the apps, as the Angular version is shared between all the apps. Although <a href="https://webpack.js.org/plugins/module-federation-plugin/#options" target="_blank" rel="noreferrer noopener">Webpack Module Federation allows mismatched versions</a>, Nx’s MFE configuration does not allow mismatched versions by default, <a href="https://nx.dev/concepts/more-concepts/faster-builds-with-module-federation" target="_blank" rel="noreferrer noopener">and you probably want to keep it that way</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-267"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-265">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-266'
	>
	Our solution</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-270"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-268">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-269'
	>
	There is really no silver-bullet solution for this, and each time you update dependencies, you might end up with unique challenges. One thing we can recommend is to update third-party packages as often as possible, in order to run into smaller sets of issues each time you do the update. If you wait too long, there will be a large amount of changes, and handling them all at once can be overwhelming. This advice stands for regular non-MFE apps but is even more important for MFEs inside a monorepo because many different apps share the same versions of various packages.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-273"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-271">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-272'
	>
	In-sync deployments</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-274">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-275'
	>
	The challenge</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-279"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-277">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-278'
	>
	Although one of the main goals of MFE architecture is to allow independent deployment of individual MFE applications, there are some changes that will require in-sync deployment of all apps. This can happen when updating shared third-party packages like the framework version (e.g., the Angular version) or when changing a package that is used by multiple apps (e.g., a shared utilities library).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-282"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-280">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-281'
	>
	Our solution</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-285"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-283">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-284'
	>
	It’s important to understand what makes a package a shared package. Nx constructs a graph of dependencies between all packages in the monorepo, and if a package is used in the host app and in some child app, it will be considered a shared package.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-288"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-286">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-287'
	>
	Additionally, all third-party packages from package.json are shared by default. You can control this behavior by using functions like <a href="https://nx.dev/packages/devkit/documents/applySharedFunction" target="_blank" rel="noreferrer noopener">applySharedFunction</a> and <a href="https://nx.dev/packages/devkit/documents/applyAdditionalShared" target="_blank" rel="noreferrer noopener">applyAdditionalShared</a> from <a href="https://nx.dev/packages/devkit/documents/nx_devkit" target="_blank" rel="noreferrer noopener">@nx/devkit</a>. All shared packages are loaded from the host application via Module Federation. This can be a tricky thing to figure out and easy to miss in crucial moments when you are trying to figure out why a deployed fix is not working.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-291"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-289">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-290'
	>
	If you fix something in a shared package that a child app relies on, you have to deploy the fixed version of both the host and the child app, even if the specific fix is irrelevant for the host application’s codebase. If you deploy just the child app, module federation will still load the outdated version of the package from the host app’s build artifacts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-294"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-292">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-293'
	>
	Handling deprecated packages and apps</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-297"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-295">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-296'
	>
	The challenge</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-300"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-298">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-299'
	>
	Having many different apps and packages in the monorepo will inevitably result in some apps or packages becoming deprecated and entering a support phase. There might be no (or very little) budget to keep such apps running. If there is a major change in shared libraries (be it first or third party), it might not make business sense to spend time handling the change in an old app that is out of the maintenance budget.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-303"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-301">
	<h4	class='typography typography--size-24-text js-typography block-heading__heading'
	data-id='es-302'
	>
	Our solution</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-306"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-304">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-305'
	>
	If you run into this situation, it might be best to fork the monorepo into a new repository where this major change is not executed and deploy a stand-alone version of the deprecated app. This might mean having to create a one-off host application for a deprecated child MFE app, because you can no longer use the mainline host application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-309"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-307">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-308'
	>
	Once forked, you can leave it like that for as long as necessary. If, one day, you get the budget to continue maintaining the app, you can merge it back into upstream and handle the changes that happened upstream. Because you want to keep this merge door open, it is important to commit all the migrations that happen in the mainline, so that the same migrations can be applied sequentially to the branch being merged back into the upstream. Follow <a href="https://nx.dev/core-features/automate-updating-dependencies#step-3:-cleaning-up">Nx’s guide on updates and handling migrations</a> for more details as you go along. If you want to learn a bit more about forks and upstream merges, check out <a href="https://www.atlassian.com/git/tutorials/git-forks-and-upstreams">Atlasian’s tutorial</a> on the topic.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-312"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-310">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-311'
	>
	Are Micro Frontends a good choice? You decide.</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-315"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-313">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-314'
	>
	As always, the devil is in the detail, and you should not take things at face value. At a glance, MFEs seem simple enough, but as we’ve shown in this article, there will be obstacles along the way. We have proposed some solutions in this article, and for more complex problems, we hope we’ve at least pointed you in the right direction.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-318"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-316">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-317'
	>
	Armed with all the information from <a href="https://infinum.com/blog/micro-frontends-nx-angular/" target="_blank" rel="noreferrer noopener">our previous article</a>, which addressed what MFEs are and how they work, you should now be well-equipped to make a good decision on whether or not MFEs are the right choice for you. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-321"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-319">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-320'
	>
	Based on our experience, we believe MFEs are a good fit for larger projects that are worked on by multiple teams, especially in large organizations. Some industries in which MFEs are likely to be useful are <a href="https://infinum.com/custom-iot-solutions/">IoT</a>, healthcare, education, government, and finance. Consider using Micro Frontends when starting your next project, or when breaking down a monolith, and don’t hesitate to <a href="https://infinum.com/contact/" target="_blank" rel="noreferrer noopener">drop us a line</a> if you need consultation.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/micro-frontends-implementation-challenges/">Implementing Micro Frontends – What to Look Out For</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>40380https://infinum.com/uploads/2023/07/Angular-microfrontends_hero_img-min.webp</url>
				</image>
				<title>Scale Smarter with Micro Frontends using Nx and Angular</title>
				<link>https://infinum.com/blog/micro-frontends-nx-angular/</link>
				<pubDate>Wed, 26 Jul 2023 12:29:19 +0000</pubDate>
				<dc:creator>Filip Voska</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=40380</guid>
				<description>
					<![CDATA[<p>Learn about the what, how and why of Micro Frontends – a great option for large-scale projects involving multiple teams. </p>
<p>The post <a href="https://infinum.com/blog/micro-frontends-nx-angular/">Scale Smarter with Micro Frontends using Nx and Angular</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-417"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-324">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-327"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-325">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-326'
	>
	<strong>Tackle the challenges of working on large-scale projects involving multiple teams with Micro Frontends architectur</strong>e within an Nx workspace<strong>. We present the what, how, and why of MFE, so you can decide whether it’s a good fit for your project. </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-330"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-328">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-329'
	>
	The world of JavaScript frameworks and tooling is both vast and complex, and choosing the right architecture is not always easy. Micro Frontends architecture can work well for large projects that include multiple teams, and in this article, we will give an overview of its use. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-333"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-331">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-332'
	>
	<a href="https://trends.google.com/trends/explore?date=today%205-y&amp;q=micro%20frontend&amp;hl=en-US" target="_blank" rel="noreferrer noopener">Micro Frontends is a buzzword</a> that surfaced a couple of years ago. However, we believe that the tooling has become good enough to make it a viable and stable choice for production only recently, which is why we decided to tackle this topic. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-336"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-334">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-335'
	>
	We’ll start with the types of challenges MFEs solve, point out their main benefits, and explain the way in which apps get served. To illustrate this even better, we’ve included our presentation of a demo application.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-339"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-337">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-338'
	>
	However, no solution is a silver bullet, and implementing a Micro Frontends architecture also comes with its set of challenges, which we will present in a separate article.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-342"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-340">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-341'
	>
	We should note that our framework of choice is Angular with Nx tooling, but the core concepts apply to all MFEs, no matter which tools are used. This article is also accompanied by a <a href="https://www.youtube.com/watch?v=GNj4OjKTK8Q" target="_blank" rel="noreferrer noopener">presentation from one of our Infinum JS Talks events</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-345"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-343">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-344'
	>
	Micro Frontends and monorepos – a great asset for large organizations</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-348"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-346">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-347'
	>
	Large organizations are usually split into smaller teams, where each team has its own development and release cadence and is the owner of a specific part of the final product. At some point, that work has to merge into a product that is presented to the end user as a single entity.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-350"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-349'
	>
	<strong>Keeping multiple teams in sync is hard enough from the organizational perspective, but it’s even harder to keep the codebase quality on the desired level while adhering to common coding standards.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-353"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-351">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-352'
	>
	When working with multiple teams, you also want to avoid re-implementing the same things over and over again. For example, almost every application needs some sort of authentication, and you do not want each small part of the system implementing its own login and registration flows. There may also be some domain entities and data layers that could be shared between all the apps.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-356"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-354">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-355'
	>
	All of this can become challenging quite quickly, so we need to introduce some tools to help us manage. For codebase management, we can introduce a monorepo. A monorepo is a single repository that contains all the code for all parts of the product, including all the apps and shared pieces of code. There are clearly defined boundaries between various parts of the codebase that everyone has to stick to, common coding standards are enforced, and tooling is provided for working within this workspace.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-359"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-357">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-358'
	>
	<a href="https://monorepo.tools/" target="_blank" rel="noreferrer noopener">Monorepos</a> are a popular choice among many big-tech companies, including Google, Meta, Uber, etc. It is not the only solution, but it is the solution we will explore in this article, and it works quite well with Micro Frontends. If we are talking about our monorepo tooling of choice, it is Nx workspace (more on it later).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-362"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-360">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-361'
	>
	The benefits of using Micro Frontends</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-365"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-363">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-364'
	>
	To address all the challenges mentioned above, we will introduce a monorepo with a Micro Frontend architecture. These two solutions do not necessarily have to be applied together, but they are a really good fit. The monorepo helps us to keep everything in one place and have common rules, while Micro Frontends change our build and release process to allow teams to work independently. MFEs achieve this by building various parts of the final product into separate smaller applications that can be worked on and released separately.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-368"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-366">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-367'
	>
	Micro Frontend architecture gives us some interesting abilities. There are three main benefits of using it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-371"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-369">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-370'
	>
	Independent development and deployments</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-374"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-372">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-373'
	>
	Micro applications are served under a common host application. Each Micro app is deployed independently. This allows separate teams to deploy their changes without having to wait for all teams to be ready for an in-sync deployment of all things at once.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-377"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-375">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-376'
	>
	You can think of MFEs as lazy-loading turned up to 11. With regular lazy-loading, JS chunks that get loaded are all part of a single set of build artifacts for one application. With MFEs, chunks are loaded from a different domain, and those chunks are part of some other application’s build artifacts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-380"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-378">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-379'
	>
	Sharing common parts</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-383"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-381">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-382'
	>
	Abstracting shared code into libraries is nothing new, and it can be done without MFE architecture and without a monorepo. However, MFEs take this to a new level.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-385"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-384'
	>
	On top of sharing the codebase via shared libraries, MFEs also allow making instances of modules themselves singletons across all MFE apps at runtime, even though there are multiple different builds that include the same module. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-388"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-386">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-387'
	>
	This way, the state can be shared between MFE apps in a seamless way. This is very powerful for cases when all the apps, for example, use the same authentication and authorization solution or if they all share some global state.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-391"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-389">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-390'
	>
	The way this kind of sharing is achieved is a bit technical and beyond the scope of this article, but when using Nx and Webpack, it means you have to utilize <a href="https://webpack.js.org/concepts/module-federation/" target="_blank" rel="noreferrer noopener">Webpack’s Module Federation plugin</a>. This plugin is a relatively low-level build configuration plugin for Webpack that is not that easy to use directly. Instead, we recommend using Nx, which offers an additional level of abstraction and tooling over Module Federation, in order to make working with MFEs within the monorepo a bit easier.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-394"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-392">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-393'
	>
	By the way, if you’d like to know more, our friend Klemen <a href="https://www.youtube.com/watch?v=xJFIaN_6Eu0" target="_blank" rel="noreferrer noopener">talked about Module Federation at one of our Infinum JS Talks events</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-397"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-395">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-396'
	>
	Scalability</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-400"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-398">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-399'
	>
	Once you introduce MFEs, it becomes easier to create new teams and/or bootstrap new applications that sit somewhere inside your MFE architecture. Most other teams do not need to know much about it, if at all. A new app can one day just appear as a new link in your navigation menu. It will not break existing apps or their processes, but it will be able to utilize everything that was already built. This way, you can easily scale both work organization and development, which is a crucial benefit for large organizations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-403"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-401">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-402'
	>
	How frontend applications get built and served</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-406"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-404">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-405'
	>
	Let’s dig a bit deeper and see exactly how deploying MFEs independently works.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-409"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-407">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-408'
	>
	First, we have to take a look at Single Page Apps (SPAs). With SPAs, most of the code is executed in the user’s browser, and the server plays a minimal role. Application code is written in JS and gets bundled in various files that are served statically by the server. The server doesn’t actually have any meaningful runtime; it just serves the files over HTTP.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-412"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-410">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-411'
	>
	SPAs can have a large amount of JS that has to be loaded and executed on the client, resulting in poor performance. To help with this, we often implement code-splitting and lazy-loading of different parts of the application. With lazy-loading, chunks of built JS code are served only when the user navigates to a corresponding page. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-415"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-413">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-414'
	>
	However, even if you have lazy-loading, everything is still part of one large application build process – a monolith. If you make just one small page in one part of the application, the whole application has to be rebuilt and re-deployed. As applications grow larger, this might not be enough to ensure a scalable solution that has sane build times.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-420"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-418"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-419">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/07/Diagram_02-1400x1252.webp				media='(max-width: 699px)'
				type=image/webp								height="1252"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2023/07/Diagram_02.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1300"
															width="1454"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			A sequence diagram illustrating how monolith SPA files get served		</figcaption>
	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-426"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-421">
	

</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-424"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-422">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-423'
	>
	Micro Frontend Apps allow us to take lazy-loading a step further and split the application not just into separately loaded chunks but into completely independent applications, each with its own development and release schedule. What was previously part of the same build artifact that was served by something like S3 now becomes multiple apps, each served from its own place.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-429"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-427"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-428">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/07/Diagram_01-1400x1252.webp				media='(max-width: 699px)'
				type=image/webp								height="1252"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2023/07/Diagram_01.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1300"
															width="1454"
										loading="lazy"
					 />
					</picture>

			<figcaption class="image__figcaption block-media__image-figcaption">
			A sequence diagram illustrating how MFE files get served		</figcaption>
	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-444"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-430">
	

</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-433"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-431">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-432'
	>
	Webpack’s Module Federation plugin ensures that code that is shared between different apps is made a singleton across all the apps. This way, you only have one instance of each shared module instead of each app having its own instance. You can control what is considered a shared module and what is not.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-436"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-434">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-435'
	>
	How Micro Frontends work – a demo app</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-439"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-437">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-438'
	>
	This article would be much too long if we went into implementation details and screenshots of how everything works in practice. Instead, we invite you to take a look at this <a href="https://www.youtube.com/watch?v=GNj4OjKTK8Q&amp;t=552s" target="_blank" rel="noreferrer noopener">video presentation</a>, where we show a demo application and how it works. Feel free to watch the whole presentation, but the demo part is from 9:12 to 25:42.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-442"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-440">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-441'
	>
	The demo app is a media consumption app where movies, TV shows, and music make up different sections of the app which can be separated out into MFEs, and the host application can take care of the user&#8217;s session. You can also check out the <a href="https://github.com/infinum/js-infinum-talks-mfe-demo" target="_blank" rel="noreferrer noopener">accompanying repository</a>.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-447"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-445"
	 data-media-type='embed'>

	<div class="embed block-media__embed" data-id=es-446>
	<iframe
		class="embed__iframe block-media__embed-iframe"
		src="https://www.youtube.com/embed/GNj4OjKTK8Q?start=552"
		frameborder="0"
		aria-label="Embed iframe"
		allow="autoplay; accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture;"
		allowfullscreen>
	</iframe>
</div></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-492"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-448">
	

</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-451"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-449">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-450'
	>
	Nx &amp; tooling</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-454"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-452">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-453'
	>
	Creating your own tools to help manage a large monorepo containing MFE apps is certainly possible, but it is best to use some of the existing solutions and build on top of them. Here is a good resource to see <a href="https://monorepo.tools/" target="_blank" rel="noreferrer noopener">an overview and comparison of many such tools</a>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-457"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-455">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-456'
	>
	Our tool of choice is Nx. Here are some of its many features we found useful when working with MFEs inside a monorepo:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-460"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-458">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-459'
	>
	<li><a href="https://nx.dev/packages/webpack/documents/webpack-plugins#withmodulefederation-and-withmodulefederationforssr" target="_blank" rel="noreferrer noopener">Abstraction</a> above Webpack’s Module Federation plugin</li><li><a href="https://nx.dev/packages/angular/generators/remote" target="_blank" rel="noreferrer noopener">Code generation</a>, including the ability to write <a href="https://nx.dev/docs/extending-nx/local-generators" target="_blank" rel="noreferrer noopener">custom generators</a> that suit your needs for code organization</li><li>Setting <a href="https://nx.dev/core-features/enforce-project-boundaries" target="_blank" rel="noreferrer noopener">boundaries</a> that restrict what can be imported from where</li><li><a href="https://nx.dev/recipes/module-federation/faster-builds" target="_blank" rel="noreferrer noopener">Build optimization</a></li><li><a href="https://nx.dev/packages/nx/documents/run-many" target="_blank" rel="noreferrer noopener">Running scripts on multiple projects</a> at the same time</li><li><a href="https://nx.dev/core-features/explore-graph" target="_blank" rel="noreferrer noopener">Visualizing dependencies</a> between different parts of the system</li><li>Figuring out which parts of the system were <a href="https://nx.dev/concepts/affected" target="_blank" rel="noreferrer noopener">affected</a> and need deployment after a particular change in the codebase</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-463"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-461">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-462'
	>
	Additional resources</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-466"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-464">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-465'
	>
	If you want to learn more, there are many good resources available online.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-469"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-467">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-468'
	>
	<a href="https://micro-frontends.org" target="_blank" rel="noreferrer noopener">Micro-frontends.org</a> takes a framework-agnostic approach to explaining MFEs. When it comes to Nx and Angular, Manfred Steyer has a <a href="https://www.angulararchitects.io/en/book" target="_blank" rel="noreferrer noopener">great book</a> and <a href="https://www.youtube.com/watch?v=tsIZjUAtF1U" target="_blank" rel="noreferrer noopener">a talk</a> on the topic.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-472"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-470">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-471'
	>
	Nx documentation itself has a couple of chapters about <a href="https://nx.dev/docs/technologies/module-federation/concepts/micro-frontend-architecture" id="https://nx.dev/docs/technologies/module-federation/concepts/micro-frontend-architecture" target="_blank" rel="noreferrer noopener">MFEs</a> and <a href="https://nx.dev/recipes/module-federation/dynamic-module-federation-with-angular" target="_blank" rel="noreferrer noopener">module federation</a>. You might also find it useful to read a bit about the <a href="https://nx.dev/concepts/mental-model" target="_blank" rel="noreferrer noopener">mental model of working with Nx</a>, <a href="https://nx.dev/concepts/integrated-vs-package-based" target="_blank" rel="noreferrer noopener">possible monorepo types</a>, and <a href="https://nx.dev/docs/concepts/buildable-and-publishable-libraries" id="https://nx.dev/docs/concepts/buildable-and-publishable-libraries" target="_blank" rel="noreferrer noopener">different library types</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-475"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-473">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-474'
	>
	Auth0 also has <a href="https://auth0.com/blog/micro-frontends-with-angular-module-federation-and-auth0/" target="_blank" rel="noreferrer noopener">a good article about MFEs</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-478"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-476">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-477'
	>
	Of course, there is much more; these are just some of the most prominent resources that we have come across.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-481"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-479">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-480'
	>
	Consider your options with Micro Frontends</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-484"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-482">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-483'
	>
	Micro Frontends can be a valid choice if the project you are working on is sufficiently large, with many people in different teams working on various parts of the whole solution. Nx workspace is one of the tools that can help you to keep everything well-organized.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-487"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-485">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-486'
	>
	We’ve presented the what, how, and why of MFEs, but in order to have a full picture of what using this type of architecture entails, you also need to be aware of the complexities and challenges involved.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-490"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-488">
	<p	class='typography typography--size-20-text-roman js-typography block-typography__typography'
	data-id='es-489'
	>
	In <a href="https://infinum.com/blog/micro-frontends-implementation-challenges/" target="_blank" rel="noreferrer noopener">Implementing Micro Frontends – What to Look Out For</a>, we present the common hurdles that come with Micro Frontends, along with our suggestions for solving them. Read on!</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/micro-frontends-nx-angular/">Scale Smarter with Micro Frontends using Nx and Angular</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>