{"id":23045362,"url":"https://github.com/mykeels/x-microfrontends","last_synced_at":"2025-07-24T07:40:14.136Z","repository":{"id":192670734,"uuid":"686272594","full_name":"mykeels/x-microfrontends","owner":"mykeels","description":"An open-source project that demonstrates the concept of microfrontends by building a Twitter clone with seven (7) separate React projects that seamlessly work together to create a complete web application.","archived":false,"fork":false,"pushed_at":"2023-10-08T16:38:35.000Z","size":1752,"stargazers_count":62,"open_issues_count":1,"forks_count":12,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-07T13:37:13.717Z","etag":null,"topics":["microfrontends","react"],"latest_commit_sha":null,"homepage":"https://mykeels.github.io/x-microfrontends/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mykeels.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-02T08:35:27.000Z","updated_at":"2025-07-07T11:56:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"8e8a4e42-28f9-43b4-be3d-7f0db16d4277","html_url":"https://github.com/mykeels/x-microfrontends","commit_stats":null,"previous_names":["mykeels/x-microfrontends"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mykeels/x-microfrontends","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mykeels%2Fx-microfrontends","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mykeels%2Fx-microfrontends/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mykeels%2Fx-microfrontends/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mykeels%2Fx-microfrontends/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mykeels","download_url":"https://codeload.github.com/mykeels/x-microfrontends/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mykeels%2Fx-microfrontends/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266808556,"owners_count":23987450,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microfrontends","react"],"created_at":"2024-12-15T21:19:57.082Z","updated_at":"2025-07-24T07:40:14.097Z","avatar_url":"https://github.com/mykeels.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# X Microfrontends: Twitter Clone with Microfrontends\n\nx-microfrontends is an open-source project that demonstrates the concept of microfrontends by building a Twitter clone with seven (7) separate React projects that seamlessly work together to create a complete web application.\n\nI built this as a demo for my [\"Scaling teams with Microfrontends - Every CTO's dream\"](https://www.papercall.io/talks/254933/children/254934) talk at SysConf 2023.\n\nSee [Demo](https://mykeels.github.io/x-microfrontends).\n\nSee [Slides](https://docs.google.com/presentation/d/10VkUfwX7NUJMl8jdT0q3qtk2C1RxG9AO4q-8DXjaFss/edit?usp=sharing).\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Project Structure](#project-structure)\n- [Getting Started](#getting-started)\n- [How it works](#how-it-works)\n- [Cool tricks with Microfrontends](#cool-tricks-with-microfrontends)\n- [Contributing](#contributing)\n- [License](#license)\n- [Credits](#credits)\n\n## Overview\n\nMicrofrontends are an architectural approach. They help you to break down your frontend monolith into smaller, independently developed, deployable applications.\n\nThis project serves as a practical example of how microfrontends can be used to build a complex web application with different teams working on different parts of the application.\n\n## Project Structure\n\nThe [chassis](./chassis/README.md) project composes 6 web apps, [communities](./mf-communities/README.md), [explore](./mf-explore/README.md), [messages](./mf-messages/README.md), [notifications](./mf-notifications/README.md), [timeline (home)](./mf-timeline/README.md), [verified](./mf-verified/README.md) into a cohesive web experience.\n\nEach microfrontend is responsible for a specific part of the X clone.\n\n[![X Microfrontends Demo Image](https://github.com/mykeels/rest-api-ioc-demo/assets/11996508/d835d338-2283-466e-b393-a06247a75bd2)](https://mykeels.github.io/x-microfrontends)\n\nThe outline colors in the image above show which projects are responsible for which parts of the page.\n\n## Getting Started\n\nTo get started with x-microfrontends and run the Twitter clone locally, run:\n\n```sh\ngit clone https://github.com/mykeels/x-microfrontends.git\npnpm i\npnpm run -r copy:env\npnpm run --parallel -r start\n```\n\nand open https://localhost:4000 in the browser.\n\nThis starts the 7 Frontend projects described above in different ports, along with the [api](./api/README.md) and begins building the [microfrontends library](./microfrontends/README.md).\n\n## How it works\n\nEach project uses [Webpack's Module Federation](https://webpack.js.org/concepts/module-federation/) to expose files.\n\nSee [example in mf-timeline](./mf-timeline/config-overrides.js#L16-L45), where we\n\n- expose [3 apps](./mf-timeline/config-overrides.js#L19-L23),\n- ensure there is [a remoteEntry.js file](./mf-timeline/config-overrides.js#L18) which tells webpack how to find these files.\n- and [give them all a unique name identifier](./mf-timeline/config-overrides.js#L17), which we get from the package.json.\n\nThe above actions form 3 concepts called `module`, `entry`, and `scope` respectively, where a microfrontend can expose one or more `module` apps, under the same `scope`, with an `entry` that tells webpack how to find them. These concepts are helpful for understanding what comes next.\n\n### Dynamic Remote Resolution\n\nThis project uses Webpack Module Federation's [Promise-based Dynamic Remotes](https://webpack.js.org/concepts/module-federation/#promise-based-dynamic-remotes), where instead of having to manually specify each remote in the chassis project, we can resolve the values for their `scope`, `module` and `entry` at runtime.\n\nWhen running locally, these values are obtained from the microfrontend manifests served by the [api project](./api/README.md) at http://localhost:3333.\n\n### What are microfrontend manifests?\n\nTo aid in dynamic remote resolution, each microfrontend publishes a `microfrontend-manifest.json` file that contains information about how to load itself.\n\nSee [example in mf-timeline](./mf-timeline/public/microfrontend-manifest.json#L2-L5), where we have a\n\n- scope: `timeline`\n- module: `./unused-root-module.js`\n- entry: `http://localhost:4001/remoteEntry.js`\n\nNotice that the `module: ./unused-root-module.js` is incorrect compared to the [3 exposed apps](./mf-timeline/config-overrides.js#L19-L23) in its webpack module federation config. This is because the manifest can have multiple [slots](#what-are-slots) modules, so it helps to reserve the root module for route slots.\n\n#### What are Slots?\n\n[Slots](./mf-timeline/public/microfrontend-manifest.json#L6-L27) are how we are able to express within our `microfrontend-manifest.json` file, that we have exposed more than one app in our module federation config.\n\nEach slot represents an exposed interface, that:\n\n- inherits its `scope` and `entry` from the root manifest,\n- may inherit its `module` from the root manifest,\n- may contain other parameters that can be used in choosing which slots get rendered.\n\nSlots can be rendered either:\n\n- directly on the route with [MicrofrontendScreen](./microfrontends/src/components/MicrofrontendScreen/README.md), making them a route-level slot.\n  - To specify routes, you would use the `slots.routes` property of the microfrontend-manifest.json file, which works:\n    - just the same as other slots,\n    - except it requires a `\"route\": \"/explore/*\"` property, specifying its route.\n  - You can get away with having one route slot that resides in the root, especially if your exposed app includes its own BrowserRouter and handles its own navigation, relying on the `navigate` [mount prop](#what-are-mount-props) when it needs to navigate to a route controlled by its parent.\n  - Or you can choose to expose an app per route.\n    - just the same as other slots,\n    - and lets you add a `\"route\": \"/explore/*\"` property, specifying its route.\n- directly within an HTML Element with [MicrofrontendSlot](./microfrontends/src/components/MicrofrontendSlot/README.md), making them a non route-level slot.\n\n#### Loading Microfrontends\n\nWhen matching slots are found, their:\n\n- `entry` script (usually `remoteEntry.js`) is loaded on the DOM\n- we initialize the exposed `module` we want\n- using the exposed [mount and unmount functions](#mount-and-unmount), we can:\n  - `mount` the app to an HTML element\n  - and `unmount` when done.\n\n#### Mount and Unmount?\n\nEvery exposed app exports as default:\n\n```js\nexport default {\n  mount: (container, props) =\u003e {\n    return () =\u003e unmount();\n  },\n  unmount: (container) =\u003e {},\n};\n```\n\nsuch as [in mf-timeline](./mf-timeline/src/main.tsx#L818-L840).\n\n#### What are mount props?\n\nthe [mount function's props parameter](./microfrontends/src/components/Microfrontend/Microfrontend.types.ts#L56-L65) contain data and functions we pass down to every microfrontend.\n\nHaving such a simple interface instead of exporting say a React component directly is a powerful concept because it lets us abstract away the moving parts of different frameworks. Technically, this can be used to load Angular, Vue, Solid, HTMX, etc, because all we need is a way to mount HTML with behaviours to an element, and unmount it when done.\n\n### Communication among microfrontends\n\nOne of the properties of the microfrontend-manifest.json I did not talk about is the `events`, which may expose a mapping of event names to a [JSON schema](https://json-schema.org/) object that describes its data.\n\nUsing the Microfrontend Context, we can [pass an eventBus](./chassis/src/components/AppRouter.tsx#L77) to our microfrontends, which they can use to communicate across the various apps.\n\n## Cool tricks with Microfrontends\n\nAll the above sounds like a lot if there is no clear advantage. Besides the team and management advantages of independence and being able to iterate simultaneously on multiple parts of the product, here are some technical advantages to using this architectural pattern.\n\n### 1. Show off your work to a colleague\n\nImagine you're working on the Timeline project, and you've deployed your work to staging, so it lives at `https://staging.x.com/mfs/timeline/` while production is at `https://x.com`.\n\nYou could ensure your page takes an `?override_manifest` query string, so you send a URL like:\n\n```txt\nhttps://x.com?override_manifest=https://staging.x.com/mfs/timeline/microfrontend-manifest.json\n```\n\nto your colleague, and they would see the new funky thing you have in staging, in the production environment, because it would load the remoteEntry.js from staging.\n\n### 2. Debug production in localhost\n\nA tangent of the above is that when you want to test a new feature in production, or debug a problem, you don't need to wait until your code gets to production, because you can load the following URL:\n\n```txt\nhttps://x.com?override_manifest=http://localhost:4001/microfrontend-manifest.json\n```\n\nand instantly have your localhost-served copy of the Timeline project, running in the production web page, with webpack hot-reload.\n\nBe sure to limit the domains that can be used to override your manifests to `localhost` and other domains you control.\n\n### 3. Instant Rollbacks\n\nBecause we are dealing with SPAs, we can easily maintain the say last 50 deployed versions of each microfrontend, because storage and CDN are relatively cheap.\n\nThis means that if something happens with the latest 1.2.3 version of the Timeline such as `https://x.com/mfs/timeline/1.2.3/remoteEntry.js`, then we can quickly change the remoteEntry.js location to one we know that works e.g. `https://x.com/mfs/timeline/1.2.0/remoteEntry.js`, and all your users need to do is refresh to get the latest.\n\nYou could even push a notification to the web page to prompt them to refresh when this happens.\n\n## Contributing\n\nContributions to x-microfrontends are welcome!\n\nFeel free to open issues, or create pull requests.\n\nPotential contribution areas are:\n\n### 1. Sharing Tanstack Query Client\n\nI've been toying with the idea of passing a tanstack query client, as part of the `mount` function's props parameter, which will enable sharing the query cache, a very powerful tool if it works.\n\n### 2. Demonstrate communicating with the Event Bus\n\nA good example of this is the [aside-search app](./mf-explore/src/aside-search.tsx#L12-L29),\n\n- emitting a `search` event that contains `{ \"query\": \"Blah\" }`,\n- having the chassis receive the event data and log to the console.\n\n### 3. Demonstrate route-level slots\n\nTo enhance the above, the aside-search app could\n\n- navigate to to `/explore?query=Blah`, - passing the `query` as a route search param..\n\n### 4. Clean up this README\n\nOh man, I wrote this in a few sleep-deprived hours, so this could use some work. Send help!\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.\n\nHappy microfrontending, and enjoy [exploring this X clone built with microfrontends](https://mykeels.github.io/x-microfrontends)!\n\n## Credits\n\nThe original html+css code used for this demo is by [@shubhstwt on X](https://twitter.com/shubhstwt/status/1692968496010015203). Without his work on the open source [xclone](https://github.com/shubhsharma19/xclone), it would be much harder to put this demo together than it currently is.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmykeels%2Fx-microfrontends","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmykeels%2Fx-microfrontends","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmykeels%2Fx-microfrontends/lists"}