{"id":10560,"date":"2024-01-14T17:11:48","date_gmt":"2024-01-14T17:11:48","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=10560"},"modified":"2024-01-14T17:11:48","modified_gmt":"2024-01-14T17:11:48","slug":"micro-frontends-using-react-and-module-federation","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/micro-frontends-using-react-and-module-federation\/","title":{"rendered":"Micro frontends using React and Module Federation"},"content":{"rendered":"<p>Module federation allows us to create micro frontends in a pretty simple way. <\/p>\n<p>Start off by running<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnpx create-mf-app\r\n<\/pre>\n<p>You&#8217;ll be prompted for a few things (these may change in different versions of this app. so these are current settings)<\/p>\n<ul>\n<li><strong> Pick the name of your app.<\/strong> This is essentially the name of the shell\/host or main application (however you prefer to think of it). So I&#8217;m used to Shell application in MAUI, Xamarin Forms, WPF etc. So mine&#8217;s going to be named <em>shell<\/em>.<\/li>\n<li><strong>Project Type<\/strong>. We&#8217;re going to choose Application (as this is our shell application)<\/li>\n<li><strong>Port number<\/strong>. The default is 8080, but I&#8217;m going to choose 3000 (as I already have servers running on 8080 for other things).<\/li>\n<li><strong>Framework<\/strong>. We&#8217;re going to be using react<\/li>\n<li><strong>Language<\/strong>. I&#8217;m a TypeScript person, so I&#8217;m choosing <em>typescript<\/em><\/li>\n<li><strong>CSS<\/strong> Accept the default which is CSS<\/li>\n<\/ul>\n<p>Now our shell will be created. So as the prompt will state<\/p>\n<ul>\n<li>cd shell<\/li>\n<li>npm install<\/li>\n<li>npm start<\/li>\n<\/ul>\n<p>If all worked you&#8217;ll be presented by some large text stating the name of the app, framework etc.<\/p>\n<p>Let&#8217;s now create another app in exactly the same way, obviously give it a different name (mine&#8217;s about), this is one of your micro frontends, also give it a different port, i.e. 8081 if you stuck with the default 8080 for the shell or in my case 3001. <\/p>\n<p>Now go to that application and run it up using the commands below (again)<\/p>\n<ul>\n<li>cd about<\/li>\n<li>npm install<\/li>\n<li>npm start<\/li>\n<\/ul>\n<p>If all went well we have an application (the shell) running and the <em>about<\/em> application running as well. So nothing too exciting to see here, but it just goes to show we&#8217;re developing &#8220;standard&#8221; React apps.<\/p>\n<p>What we will now need to do, is create a component that we&#8217;re going to expose from this application. All I&#8217;m going to do is move the App.tsx code that shows the application name etc. into a component, so if you want to follow along, let&#8217;s add a components folder to the src folder and within that add a About.tsx file and moved the code from the App.tsx into it, so it looks like this<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport React from &quot;react&quot;;\r\n\r\nexport const About = () =&gt; \r\n(\r\n    &lt;div className=&quot;container&quot;&gt;\r\n    &lt;div&gt;Name: about&lt;\/div&gt;\r\n    &lt;div&gt;Framework: react&lt;\/div&gt;\r\n    &lt;div&gt;Language: TypeScript&lt;\/div&gt;\r\n    &lt;div&gt;CSS: Empty CSS&lt;\/div&gt;\r\n  &lt;\/div&gt;\r\n);\r\n<\/pre>\n<p>Now the App.tsx looks like this<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport { About } from &quot;.\/components\/About&quot;;\r\n\r\nconst App = () =&gt; (\r\n  &lt;About \/&gt;\r\n);\r\n<\/pre>\n<p>We need to make some changes to webpack.config.js, so locate the <em>ModuleFederationPlugin<\/em> section.<\/p>\n<ul>\n<li>Locate the exposes section and change it to look like this\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nexposes: {\r\n  &quot;.\/About&quot;: &quot;.\/src\/components\/About&quot;\r\n},\r\n<\/pre>\n<p>We expose all the components we want via this section and the shell app can then access them.\n<\/li>\n<p>In your shell\/container application we also need to amend the webpack.config.js and locate the <em>remotes<\/em> section, as you&#8217;ve probably worked out, this is going to register the micro frontends to be used within the shell\/container. So mine looks like this<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nremotes: {\r\n  about: &quot;about@http:\/\/localhost:3001\/remoteEntry.js&quot;\r\n},\r\n<\/pre>\n<p>Let&#8217;s see if this work, open the shell\/container&#8217;s App.tsx and add\/change it to look like the below<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport { About } from 'about\/About';\r\n\r\nconst App = () =&gt; (\r\n  &lt;div&gt; \r\n  &lt;div className=&quot;container&quot;&gt;\r\n    &lt;div&gt;Name: shell&lt;\/div&gt;\r\n    &lt;div&gt;Framework: react&lt;\/div&gt;\r\n    &lt;div&gt;Language: TypeScript&lt;\/div&gt;\r\n    &lt;div&gt;CSS: Empty CSS&lt;\/div&gt;\r\n  &lt;\/div&gt;\r\n  &lt;About \/&gt;\r\n  &lt;\/div&gt;\r\n);\r\n<\/pre>\n<p>Run the <em>about<\/em> app and then the shell and if all went to plan you&#8217;ll see the &#8220;About&#8221; component in the shell.<\/p>\n<p><strong>A little more in depth ModuleFederationPlugin<\/strong><\/p>\n<p>This is really cool and we can see much of the work is done on the ModuleFederationPlugin, so let&#8217;s look a little more in depth into some of the key features<\/p>\n<ul>\n<li><strong>name<\/strong> is the name we&#8217;re giving to our application<\/li>\n<li><strong>library<\/strong> is used to determine how exposed code will be stored\/retrieved<\/li>\n<li><strong>filename<\/strong> by default is remoteEntry.js, but we can name it whatever we want, for example remoteAbout.js for our <em>about<\/em> app<\/li>\n<li><strong>remotes<\/strong>, as we&#8217;ve seen these point to the &#8220;modules&#8221; we want to include and have the format\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&quot;app-name&quot;: &quot;name@remote-host\/entryFilename.js&quot;\r\n<\/pre>\n<\/li>\n<li><strong>exposes<\/strong>, as we&#8217;ve seen also the <em>exposes<\/em> is used to expose components etc. from our micro frontend, it has the format\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&quot;name&quot; : &quot;location-within-app&quot;\r\n<\/pre>\n<\/li>\n<li><strong>shared<\/strong> is used to share node libraries which the exposed module depends on.<\/li>\n<\/ul>\n<p><\/p>\n<p><strong>Code<\/strong><\/p>\n<p>Checkout an example <em>shell<\/em> app with three Material UI\/React micro frontend apps at <a href=\"https:\/\/github.com\/putridparrot\/blog-projects\/tree\/master\/microfrontend-react\" rel=\"noopener\" target=\"_blank\">microfrontend-react<\/a>. Each app. uses Material UI and the <em>shell<\/em> app. brings them together to create the basics of an application with header, navigation bar and some content.<\/p>\n<p>Obviously there&#8217;s a lot more to do to have a truly interactive micro frontend based application, but it&#8217;s a starting point.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Module federation allows us to create micro frontends in a pretty simple way. Start off by running npx create-mf-app You&#8217;ll be prompted for a few things (these may change in different versions of this app. so these are current settings) Pick the name of your app. This is essentially the name of the shell\/host or [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[714,243,257],"tags":[],"class_list":["post-10560","post","type-post","status-publish","format-standard","hentry","category-micro-frontends","category-react","category-webpack"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10560","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=10560"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10560\/revisions"}],"predecessor-version":[{"id":10567,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10560\/revisions\/10567"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=10560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=10560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=10560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}