Microfrontends should be a last resort
breck-mckye.com
breck-mckye.com
Everyone thinks because they can create "small reusable slices" of full frontend code that this comes for free without a load of problems that get in the way of the mythical land. The only issue is everyone who has tried microfrontends is universally full of regret.
Other attempts at this are:
1) having an enforced centralised library of components (this just about works) - how this is managed and the engagement with other teams is critical.
2) turn everything into an npm package and create version hell at the end of a sprint as hundreds of devs try to version bump everything and the main package.json all at the same time.
3) free for all with moving people regularly between teams. This is the best solution because best practices automatically filter their way through each team through the people and everyone learns and gets on with each other in a human way that allows real collaboration.
4) splitting vertically rather than by components so one team does the search UI another does the homepage another does the product detail etc. but hopefully in the same technology!
Or you could probably just reduce the number of people adding pointless features to your ecommerce site... Ah there is five of you and you did microfrontends didn't you, I can't and won't help you then :-/
My team, at least, did not have the necessary support structures in place to help others who wanted to maintain their own UI. I see this mostly when crossing framework/language boundaries (mixing React + Angular in a SPA, as it was in my case). They declare microfrontends, but then all the component libraries were all React-based anyways.
It just ended up being a mess of N deployment processes, N build systems, N storage buckets, zero standardization whatsoever, and mountains of technical debt, all without much benefit.
...but if you're all working in the same language/framework where that component/style-lock-in is acceptable, why would someone use a microfrontend to begin with? Can the organization not set up a single repository with different teams contributing to it? One deployment, one build system, one storage bucket, and standardization?
IMO CODEOWNERS is the original and best "microfrontend" solution for small-to-medium-sized teams working on a single product. If you have hundreds or thousands of engineers (think FAANG) working on a single experience that just HAS to be a SPA, then maybe you have the resources to build out those support structures and actually get MFEs to work on an organizational level.
In the vast majority of cases, however, I see it as a bandaid on an organizational problem that's eaten up because it's an interesting technical challenge for senior engineers to think about (someone made a great comment about "drawing the perfect box"), and because management thinks it's a cool trend with benefits they can grok.
When you're building server architectures, it's fine... You have more storage than every book ever published in the 1800s on each machine you're deploying to, you can afford to have microservice A depend on library set Q and microservice B depend on library set R and as long as the public-facing contract doesn't change, nobody cares. Your deployment infrastructure does something to get all those dependencies in place (possibly even something hugely inefficient) and you're happy.
Efficiency of deployment still matters for the client. It is not okay to be shipping four different date libraries because your client is an MFE and the different departments in your company can't agree on what core library to use. That scales in the reverse direction: you're paying for bandwidth (and your users for time waiting for your site to load) per user. It's waste you can feel.
Composable tools exist. Whatever horseshit is going on around ANY bigger sized application is not. Excel, any random React app, GIMP… sure, compositional engineer might be taking place WITHIN the application, but it is barely composable beyond a Copy, Paste, Save As dialog and the ability to arrange the window with other windows.
Can’t you see how things immediately invert and turn inwards, away from interaction, away from composability, the moment the turn towards structured interfaces begins?
An API is a narcissist. You have to live in its world. A Unix pipe is a communist.
Think, aggregate vs combined in terms of the GPL… pipes vs APIs…
During the Q&A somebody asked a question about their company's struggle to move their monolith to micro services and the CTO asked two questions that, at the time, was very illuminating: how many teams did they have and how many developers were in their tooling team. When they said they had a relatively small team the CTO said "you don't have any of the problems micro services solve, why are you switching".
This has been my experience with conferences lately: Way too much emphasis on the next big trend, to the point of being counterproductive for actually getting work done
Certain teams and companies live and die by conference trends. If you can't also show interest in those trends, they don't want you.
I was asked to review hiring practices for the front-end team at a company I worked for a couple years back. They had a long list of questions about the latest web technologies and frameworks that they used to screen candidates. I was puzzled because we didn't use many of the technologies they listed. Several of them weren't even stabilized standards that could be used in production. The team lead explained that knowing about them was his primary signal for someone's overall competence.
They hired a lot of "smart" developers, but they also took forever to ship anything. They were always trying to do things like micro front-ends, rewrite part of the app in the latest framework, experiment with new web technologies that were too immature to ship, and other things that weren't really related to getting product out the door.
God help us.
Good luck, I think God is too busy refactoring his Perl code.
> "I mean, ostensibly, yes. Honestly, we hacked most of it together with Perl."
The three easiest ways to get someone's attention in a title are: being a well known speaker, talking about a giant project, or talking about a trend.
As much as there is value in "tricks to avoid false negatives during CI" it just isn't as catchy.
I don't know if it's the primary signal, but I think you need a balanced team. It's a good idea to have at least one person on your team who's staying on top of what's going on in the front-end community. But you have to be careful that person isn't blindly trying to apply every trend in your product, e.g. resume driven development.
I don't know about this. I've been able to convince several developers to put down their shiny in favor of trying out some classic options. They seem to enjoy their newly-discovered traction. Progress feels good regardless of how you're achieving it after a while.
I did have to provide starting points & patterns, but it didn't seem to take much. I think they key is proving the value around why the old tools are (likely) better. Just lecturing a young person verbally about this and that is almost certain to send them even deeper into their rabbit hole.
If the mission is vague with uncertain upside associated with completion, you will absolutely find everyone fucking off in different directions as convenient. If you somehow frame the mission more like "ship by Christmas and everyone gets a 50k bonus", you can usually convince even the biggest 'not my job' assholes to adapt to changing realities.
Leadership is at the heart of why some companies are simple and others are running a technological clown show.
Awesome. There are plenty of programmers who aren’t magpies distracted by shiny trinkets. I hope they get jobs. They can take the seats of those people who can’t bear not wasting time on the next new fad.
Keep your friends close and your enemies closer.
Most developers / teams / companies are just working rather than doing conferences. There's a whole world of development that is sort of opaque / assumed to be backwards.
Ask, "Pick a popular buzzword that you think is often a bad idea. Name it, explain what it was, explain why people like it, then explain why it is often a bad idea."
If they hesitate, reassure them, "It will be fine even if I disagree with you. I just want to see that you can think for yourself."
I've been going to tech conferences for 25 years. This isn't a new new trend. :-)
Oh man does this resonate with me. Some of the "smartest" people we've hired have also been the slowest to deliver as they waffle and perfect and theorize and play with the tasks they have.
There is a difference between being smart and effective
It almost immediately gets rid of a lot of idealism.
Overengineering is the devil
Of course I don't actually think that, but there does seem to be a kind of parochial navel-gazing that comes with the high intellect territory, and in tech that manifests itself in absurdly over-engineered solutions.
Have you tried not going to conferences? I'm saying that with a good bit of sarcasm, but frankly look at where a lot of these things occur and who speaks at them. They occur in huge cities that curiously have beaucoup tech companies; companies that we know incentivize promotion based on things like "personal brand" and new project development as opposed to impact. Companies that often time give lots of money to those same conferences.
My point here is that conferences today are inherently inorganic and you'd get a lot more value reading long form blogs and going to meet ups to talk to people about the curious problems they have.
always has been dot jpeg
I remember GlueCon 2012, just wall-to-wall NoSQL hype, with a dash of microservices on top. Anyone who ran home and implemented stuff from those talks was absolutely wasting their time (me included).
The killer truth is, the connections between your components start to become more important than the components, and the work to maintain this system is only really justifiable if the components can be worked on in parallel.
But that never happens, and now you spend all your time trying to herd cats. Embrace a monolith, modularise the code, discuss your work with your colleagues so you don't step on each others' toes.
We're here to build systems, not pet-projects/fiefdoms. There is no software architecture that will allow you to work in isolation.
There's a balance and the "every function should be a microservice" approach is kind of insane, but "just use a monolith for everything" falls apart pretty quickly at larger team sizes.
What is a problem in itself. On every sane place, most of the "services" aren't providing any on-demand service, instead they are just thematic monoliths doing all of a part of a task.
I'm settling on the opinion that a service-based architecture is always wrong. But people keep calling the good architectures by that name.
Yes, all the good architectures are service based. And all service based architectures are wrong. Because all architectures are wrong.
In the sense that there’s always another way you could have architected it that would be better for where you think you want to go next, than the way it is architected.
Learn to accept that an evolving software system is always going to have a suboptimal architecture.
You are misinterpreting my words here. I'm saying that I now strongly suspect that biasing the way you divide your software on a direction that gives you services will always make your life worse (probably by a lot). There's no philosophical allegory about perfect things not existing.
There are a few things that really want to be services. You'll settle those on services whatever way you decide to architecture your software. But those are very few, and any push into doing it for more than the absolute minimum is harmful.
> "just use a monolith for everything" falls apart pretty quickly at larger team sizes.
Absolutely! Don't put everything in a single monolith, develop several mediumliths with lower requirements for coupling code together, but keeping it small enough so that upgrades are bearable.
This is to say nothing of the classic dependency hell[0] where the main app depends on library X and Y, but library X depends on Z==1.0.0 and library Y depends on Z==2.0.0. At which point you have to do some hacky stuff like JAR shading (which has its own problems, see log4shell) or vendoring the dependency under a new namespace.
For a lot of use cases, specifically at larger orgs and where highly optimized performance isn't a big priority, the networking and operational overhead is a small price to pay for decoupling.
Please understand that every environment, company, and project is different.
You are completely right, every project is different, and that's why the general idea of microservices is bad. Split your services where there are technical or heavy political and organizational reasons to do so, but don't go for splitting as your default solution.
I've seen that so often it now feels like a sarcastic meme to me.
The org structure changes much faster than your code structure does. Good luck getting those two to stay in sync longer than the CTO stays in their role.
No doubt, but my point is there is a unifying metric that we can use to evaluate the effectiveness of these environments, Percentage of time spent on the environment itself versus on user needs. I think that number is too high for any system that is overly-decomposed.
You mean…
spend more time drawing boxes and fantasising about what tech would be 'just-perfect' for that particular box?
Won’t that mean the connections between your modules start to become more important than the modules, and the work to maintain this system would only really be justifiable if the modules can be worked on in parallel?
Often the pain of supporting this is so high you will just refuse to ask if the API can be improved despite the pain of the bad API.
The problem is, micro-things require better high-level direction, to avoid becoming a tangle of poorly integrated, poorly performing, expensive things.
If end users can tell you're using micro-frontends, you've done it wrong. If you need 20 people in 10 meetings to change your app's chrome, you've done it wrong. If you don't know how and why these problems won't crop up for you before you've gotten started, you're going to be doing it wrong.
You need a strong architecture group, and the buy-in of the micro-thing implementors to take responsibility for their place in the whole to pull off.
Solving a balkanized, poorly integrated services often goes through restructuring the business teams and realign them under a single umbrella. I see it as the poster child for "solving technical problems through social solutions"
They're only 2.5 developers -- .5 because one of their juniors is practically useless. The reason they went with it is because the "senior" in charge wanted to experiment, which can be all well and good in certain contexts, but they've had nothing but trouble. Instead of doing the reasonable thing and stepping back and thinking "Okay, solving <very common frontend problem> shouldn't be this hard. Maybe we should rethink this MFE approach", the "senior" just keeps piling more turds on top of their already huge, steaming pile of turds.
Examples: The MFEs(which live in iframes) need to be able to tell the umbrella that a certain keyboard shortcut was pressed. Normally this would just be an `addEventListener` call by whatever component is interested.. but with iframes it's not that simple. Solution? Capture every keystroke in the application in all the MFEs and send them, as JSON, over your custom messagebus.
Because they use graphql(with apollo client), every graphql request should be cached and you can set up "rules" to do optimistic mutations and whatnot. You should be able to show a lot of UI instantly to the users because you already have data cached. But the caching obviously doesn't work across iframes.. so they tack on yet another hacky solution to transport the cache across iframes sometimes when it's necessary.
Anyway, the point isn't to rant about this specific scenario forever, but rather explain how fucking awful MFEs can be when you make the wrong decision. They are very obviously building a monolith and MFEs should never have been considered, even if you don't look at the team size of 2(which is enough to make the decision ridiculous on its own). I honestly don't think there are any real use cases for MFEs outside absolutely massive organizations working on very specific kinds of products.. maybe stuff like cloud platform management UIs.
If your company is small, don't bother with any of these micro trends. The overhead of micro architecture is non-trivial: telemetry, tracing, test infra, build infra, non-prod environment setup, etc.
It’s obvious that strong walls have immense cost, but perhaps for a large enough organization it enables faster movement overall with fewer faults. Walls are good after all.
What’s fascinating to me about micro-anything vs. monolith-anything is it’s much more a function of team structure and culture than of technical merit. In some cases, the technically inferior solution can deliver more to the business when combined with the unfortunate realities of human development.
I agree with the original offer that micro-anything should ultimately be considered a failure of better modularity mechanisms.
I want to be clear that I don't think microservices are a good idea for most companies. I just disagree with "Micro-anything is the philosophy based in the presumption that your engineers will not respect softer walls and modules and therefore strong ones must be constructed." It's not about the walls, it's about the independence of development and deployment. There are easier ways to enforce walls without such ridiculous operational and technological overhead.
So in case of microservices/microfrontends you gain minutes on build time but lose hours/days on deployment and verification.
However, I still think this is fairly related to what I was trying to convey because it's related to the _process_ of the engineering vs. the technical merit of the deployed solution. The tradeoff space you're describing is pretty much a function of how big the team is, how it's structured, the products uptime requirements, deployment frequency, etc. as opposed to the technical merit of the design in isolation.
I don't think I worded it particularly well in my original comment, but I think these tradeoffs are interesting and frequently people talk past eachother about them because the 'right' decision depends on all the non-technical factors of the product.
Absolutely this, true in both the back and front ends. The first step to breaking apart any monolith is the extremely boring refactoring process. People want to skip over this because it's not the sexy cool part where you're using Kubernetes and lambdas or whatever other tech will look great on your resume. But I'll say that every monolith->microservice (or MFE) move that I've seen, whether or not it was successful was entirely determined by if the upfront refactoring work was done.
I interviewed at a place a couple months ago that was looking for an front end architect, and all the assumptions and questioning were that their use of microfrontends (both angular and react) was a good thing and how would I make teams follow this approach.
They passed on me when I made it clear that I didn’t think it was a very good approach for their smallish team, and in general that the challenges they were experiencing were mostly because of this architecture, not solved by it.
This means that you lose independence and doing A/B testing becomes very difficult when you can't really control what the user is seeing because the version is pinned.
A micro front end allows you to deploy independently, test independently, and truly own your code. Network hops are reasonably cheap for most consumer applications and collaboration on a shared component is very expensive.
I'm speaking from the perspective of a checkout flow, which my company is actively ripping out from the monolith in order to ensure people outside the monolith can use it AND to ensure we're able to do the price testing/conversion rate testing at a level that doesn't need a separate suite of tools for each business unit. This also has the benefit of reducing integration points with the billing system leading to better standardization and consolidated data in one billing system.
vite, esbuild, parcel etc. have not adopted anything around this.
To me, that says that those putting out the nuts and bolts work that having been leading this space for several years either haven't spent alot of time evaluating them, or have found them overly complex for what they are, or perhaps think there is a better way to accomplish their goals.
I'm not sure MFEs are the best tech, to be honest. I've seen demos where it seems to be an addition (bootstrapping speed, neat tricks with routing etc.) but I've never seen them demonstrated in practice. I'm on a team now that is adopting MFEs and our payload is somehow considered acceptable at 8 MB. Given this is a behind-the-login app, I think somewhere between 300-500KB bootstrapping and getting to interactive with the rest lazy loaded is fine, but 8 MB to boot the app seems like we aren't doing even basic optimizations (I unfortunately do not have the control I wish I had on this)
I'm really unsure about MFEs, they seem like something looking for a problem in practice. They certainly appear hard to get right
I am working on a MFE shell application for a product (or rather a suite of closely related applications/products), that need to be presented to the users as a single system. Ballpark figure of the business unit 400+ software developers and 80+ modules/sub-products.
I think the MFE architecture was a justified trade-off, given our organizational structure and product landscape, but one should be very cautious if it is presented as a some kind of default solution.
That feels right.
Another I've been apart of is applying it to a given codebase post acquisition, helps speed up integration in some respects
One example I've seen floated though is remote modules for design systems. This one I'm unsure about. I can only speak from one experience when this was tried and it was a disappointing result.
And according to some folks on Vite conf it will be soon supported natively
Avoid unless you know you reallllly need them.
First, MFEs solve organizational issues by cheaply offering release independence. An example is when teams that do not overlap in working hours. Triaging and resolving binary release blockers is hard to do correctly and onerous on oncall WLB. Another example is when new products want to move quickly without triggering global binary rollbacks or forcing too fast a release cadence for mature products with lower tolerance for outages or older test pyramids.
Second, MFEs are a pragmatic choice because they can proceed independently from the mono/microrepo decision and any modularization investment, both of which are more costly by several multiples in the cases I've seen. Most infra teams are not ivory towers and MFEs are high bang-for-buck.
Finally, MFEs are a tool to solve fundamental scaling issues with continuous development. At a certain level of commits, race conditions cause bugs or build breakages or test failures, and flaky tests cause inability to (cheaply) certify last known good commit at cut time. You can greatly push out both of these scaling limits with good feature flag/health-mediated releases and mature CI, but having an additional tool in the kit allows you to pick which to invest in based on ROI.
Advocating for modularity is nice but I've never met an MFE advocate who didn't also want a more tree-shakeable modular codebase. We should not jump to the conclusion the MFE as bad or a "last resort" because there exists another solution that better solves an partially overlapping set of problems, especially if the other solution doesn't solve many problems that MFEs do or requires significant more work to solve them.
[1] Runtime JS isolation (e.g. of globals set by third party libraries) is hard and existing methods are leaky abstractions like module federation or require significant infra work like iframing with DOM shims. CSS encapsulation is very hard on complex systems, and workarounds like shadow DOM have a11y and library/tooling interop issues. Runtime state sharing (so not every MFE makes its own fetch/subscriptions for common data) is hard and prone to binary skew bugs. Runtime dynamic linking of shared common code is hard to reason around and static linking of common code can result in the same transition of a lazy loaded module to go from taking 10kB to 1MB+ over the wire.
Wanting to couple that with the JS ecosystem, I don't even want to imagine that.
It’s not just state. It is the kind of state. Think about the difference between aggregate and combined software systems, and I’m using the GNU and FSF definitions here. Loosely coupled systems with pipes? Aggregate. API interface? Combined.
Every step away from something as generic as a stdin/stdout pipeline brings you more and more coupling.
You want to know the real problem with contemporary software development? We don’t actually compose our tools together beyond some meatheaded level of “specialized database”, “specialized frontend”, “specialized backend”.
Cat, awk, grep, sed, and most importantly | and < and > and you can compose any number of specialized tools.
The inclusions of libraries of code into a single executable environment that exposes an HTTP API is a non-generic data interface to another software system. Only generic interfaces are truly composable.
I’m still long on void *…
Nevertheless, one thing to keep in mind (and I do consulting on MF for the last 5 years) is that most projects / teams are not well prepared and actually not at all suited for MF. MF solutions are usually just done from a technology POV, which is already a problem. Next thing is that the used technologies are often also not well suited. People tend to use strongly coupled things that just create hidden monoliths. In the end projects fail often because either the organization is not ready to have truly independent teams or / and because the software has just become too complex and unmaintainable.
To end with something positive: We also know many success stories in that area where people spent the right amount of research on what technologies to use and where everyone in the organization was prepared to accept the new teams setup.
Are any of these “many success stories” talked about online? Case studies we can get pumped on?
1) Monorepo with multiple workspaces
2) With several separate independently deployed applications, each maintained by a separate team
3) That share a set of common packages for common stuff (auth, etc) with full typescript definitions
4) Add CI to typecheck if any shared package changes types you get errors
5) Preferably with the packages being able to be independently run for development (something like storybook, although I don't recommend it)
6) Preferably with the packages being kept small, lean, with limited number of external dependencies (ie, settle on the cross-team deps to use, so framework, routing, data-fetching, etc)
7) Some kind of pre-commit git hook or CI script to validate a set of core shared dependencies used by packages are kept in sync (ie, everyone is running the EXACT SAME React version). I use this one: https://gist.github.com/DanielHoffmann/a456aadb2f27880d59241...
8) Shared build configuration and tools, all apps are validated, built and bundled by the same code.
9) NO PACKAGE PUBLISHING/VERSIONING, all dependencies are workspace:*
For example:
folder-structure:
/apps/{team1-app-name}/
/apps/{team2-app-name}/
/packages/auth/
/packages/some-util-lib/
/package.json
"scripts": (test, lint, format, typecheck all done at the top level package.json)
"workspaces": [
"apps/*",
"packages/*",
],
/packages/auth/package.json
"scripts": (dev to run in development mode)
"devDependencies": { "some-util-lib": "workspace:*", "react": "^18.0.0" }
"peerDependencies": { "some-util-lib": "*", "react": "*" }
/apps/{team1-app-name}/package.json
"scripts": (dev to run in development mode, build for production builds)
"dependencies": {
"auth": "workspace:*"
"some-util-lib": "workspace:*"
}
This doesn't give you 100% of the independence of microfrontends, but it does give you quite a lot of bang for your buck. Depending how much independence or reuse you want you might want more or less shared external dependencies (for example your shared packages could be framework agnostic and just use raw JS)The build/bundling configuration can set up separate chunks for the core set of shared dependencies (react, router, etc) to improve build times, load speeds and caching*
Some smart branch management so teams can work independently seems better for me. For example each project gets their own production branch and development branches to trigger deployments and can pull changes from master as they see fit.
If you are planning on these shared components and dependencies be versioned I highly advise against that, the permutation of versions of underlying common libraries (like React) can make an incompatible versioning hell where component X works on React ^16.0.0 but in practice was tested in React ^18.0.0 only. In my own project I explicitly force all shared dependencies (which I try to keep to a minimum) to be on the same version.
> without the need for built-time coupling
There are two ways of having build-time coupling:
1) Shared build/bundling code, configuration and tools
2) Single build/bundling for all the code
You can most definitely have independent projects sharing the same build/bundling code, configuration and tools while every project is built separately and independently. This can make it hard to integrate with solutions that rely on taking over your bundling though.
All these nonsense approaches like "microfrontends" feel like they're still fighting that war.
We're finally at the point there reasonable isolated components are totally doable within the web platform. We just need to lay down the rules for good practice to keep the inherent globalness of the web from creeping back in and ruining everything.
A monorepo with separate build pipelines is better, but still unnecessarily complex.
A framework like Next.js can do the heavy lifting for you. One build pipeline where components are shareable, and pages/routes ans entry are isolated during development and can be deployed independently if required.
It’s often referred to as Packaged Business Capabilities.
The MFE is an adapter pattern that hosts discrete modules deployed from their own repositories and configuration should be automatically integrated.
But as the OP states, there are many ways to do this badly. A strict non-abstraction discipline is required. No shared utility libraries between modules.
There's not much magic or difficulty with MFE.
It's the same as when you break your program into multiple libraries, and you just do it all the time.
The moment you do npm install, pip install, cargo install,... you're basically doing the Micro-program already.
Imagine you have a website with some kind of router for different paths. You might also have a unique domain per market (e.g. amazon.co.uk or amazon.jp)
/ -> home page repo
/search -> search repo
/products/xyz -> products repo
/products/xyz/review -> product review repo
It might seem crazy to have so many repos, but each of these pages already imports so many different components from different teams, and separating them is an easy way to make sure you don’t accidentally separate something else.
You could use Gatsby to prebuild all the products pages when there’s a change in the CMS and serve them on S3, and you could use a Next.js project to handle the /search page. You could use Vue to do the reviews page, or just have a normal create react app SPA. It gives you flexibility to experiment and lets teams not stop all over each ofher.
If your build step results in 20 * 300 product pages, then you’ll be glad to not have other stuff in that repo.
Of course you could accomplish this in a monorepo, but I’m just using project & repo to mean the same thing (a micro frontend)
It gets easier to A/B test and you could deploy a different site version for different markets (e.g rollout a new search result layout in Ireland and see if there’s a difference in click through rates). It’s just easier to deploy a MFE to serve that route in that market and have the old MFE still deploy to other markets.
Amazon famously built the company with OBIDOS, a monolith; these days, backend microservices abound — as do what we’re calling here microfrontends, although my understanding is at AMZN they are granular not just to market-specific domains or route prefixes, but sometimes also to pre-defined sections of a final rendered page. Would love to hear from AMZN engineers that work on such things.
Wouldn't the point be to keep the style consistent anyway?
Keeping style consistent is actually harder using microfrontends compared to shared libraries. It is more about letting each application choose its own tech stack and not be burdened by the other application's tech debt.
We have multiple web apps (Angular, but also some legacy JSP ones) that are currently hosted on different domains. Some of them are part of a product suite (see JSP), and some of them are separate products themselves. However all of them target the same users :
1. Our Customers
2. Our employees (dev, service, support teams)
Those products have a complex way of authenticating and storing user data, since we haven't got a centralized auth server. So we keep multiple copies of user data, and authentication mechanisms, which leads to duplication, trouble in syncinc changes etc.
Also, our customers, need to log in to different systems each time they need to work on 2 separate products, let alone that the UI/UX might be quite different. This leads to frustration, confusion and bad UX in general.
At the moment, we are implementing a centralized authentication service, which means that we can finally integrate users across systems. However we are trying to re-architect our frontend applications also, that's why I've been exploring microfrontends.
My first attempt, will be to integrate the Angular apps under a single login page which leads to a host app that will only handle :
1. Users (login/logout/manage)
2. Navigation (Send me to the required web app)
I have already used module federation (webpack) to integrate a new web app (module), into an existing product and it has been working fine for some time. So I am exploring integrating all of the Angular apps under a single host (new webapp), and using module federation (or whatever else works) to fetch and run the other modules, with routing (lazy loaded, remote modules)
It's worth noticing that our 2 main products I am trying to integrate, are Angular SPAs that use the same UI framework, and similar UI/UX. There are 2 (currently) small-sized teams that work in these projects, and they have their own release cycles. Each project has its own backend service.
The issues I have identified so far are :
1. Angular/package upgrades must be done simulatneously (if we care about performance, and don't want multiple copies of the framework downloaded and running in the same page)
2. JWT token sharing/refreshing (Since everyone will live under the same domain, we can share auth tokens in cookies/headers, but we require a mechanism for all apps/modules to request a token refresh, and a way to communicate user status changes : user logs out, permissions have changed etc) (p.s. Backend services - hosted in separate domains - will of course have to integrate the new Auth service, and inspect/validate the shared JWTs)
3. ALthough module federation might work for Angular SPAs, we will have to implement a separate mechanism for importing JSP apps (iframes probably?) and the way we share JWTs with them.
Since I've read a lot of constructive critisism on the issue here, I would love any feedback regarding my approach. Is there anything else I should explore? I've thought about NX monorepos, with separete CI/CD pipelines for each project, but that looks more complicated from where I stand.
Thanks in advance.