module-federation-examples icon indicating copy to clipboard operation
module-federation-examples copied to clipboard

Fallback to lower version of shared library with singletone: true

Open cooltolia opened this issue 3 years ago • 4 comments

Hey again. I would like to raise one more question. I feel it is more concrete and I hope valid than the previous one.

So, we have to applications. App1 exposes a couple of components and have React v17.0.2 library as a shared singleton one. App2 consumes those components and also have React but v17.0.1. Both have strictVersion: true

At this point everything works perfect, we have only one higher shared version of react.

But at some point of time App1 moves further and updates to React v18.0.0 And it breaks App2, cause major version of React is not a valid option, so App2 crushes.

So and here is the question. Is there any way to let App2 in that case fallback to it's own lower version of React and continue working?

cooltolia avatar Apr 22 '22 16:04 cooltolia

look at the different-react-versions example.

youd have to use adapter modules and maybe look at the advanced MF api to share reace 18 on a different share scope for newer remotes.

that was theres two react singletons v17 and v18. on differnt share scopes just for that package. and you can use an adapter and some way to detect, like maybe export a metadata on the exposed module like export const usesReact18. so when consuming you can check for that flag and mount v18 with an adapter module to a ref, then proxy props back and forth via just calling render or hydrate again on the ref

ScriptedAlchemy avatar Apr 29 '22 05:04 ScriptedAlchemy

Feels like this might become a fairly large issue now the community starts moving towards React 18. We have around 10 apps sharing a design system header via MF, as well as some apps sharing modules from app A to app B and C. Upgrading React to 18 and moving everyone towards supporting createRoot will be a big challenge moving forward due to MF, since we are now more coupled than before. I fear that MF might start getting some push-back due to this, maybe there should be a better and easier story with MF when it comes to doing something like this?

Wrt this specific issue, wouldn’t it be better to drop the strictVersion flag? Combining that with singleton seems to have a very high risk of breaking in production/runtime. Hopefully caught first by tests of course.

einarq avatar May 21 '22 07:05 einarq

Yeah dropping strict version would be the way.

Regarding react 18, yes - but this is a systems design problem. If you're using MFP as a polylith - then this is harder but ultimately solvable. Adapter modules would be the way to go and load another copy of react to mount a sub app to a ref.

Software should be able to run standalone. That said. I'm testing the interop between R17 and R18- if the api is similar, from a jsx standpoint - then it should be mostly backward compatible under a react 17 host. You'd probably have to guard against use of new apis like createRoot, but chances are you could migrate apps & limit using modern features that can't be patched for other hosts.

If you are using polylith architecture- you're building a distributed monolith. It'll behave as a monolith would.

One possible scenario would be to see what the interop is between react 18 and 17 - if you use 18 without concurrent mode - how similar does it behave to react 17? I'll probably know more in a few weeks as we are actively upgrading federated applications from 17 to 18.

I'm not too concerned with pushback generally this is a transitory problem & only impacts certain apps using a specific arch. 16 to 17 wasn't a big problem - 17 to 18 probably will be the same.

I agree this is a negative effect of the simplicity of MF - however I believe this is is a problem that'll fade away with v18 since async render support exists. We likely won't face such a steep problem when with async. Backwards compatibility or versioned remotes is encouraged for large scale systems. If teams can pin to older deploys of remotes - they don't get featur updates sure - but they'll keep working.

Probably the biggest perk of MF, to me - it demands better arch and maintenance. Tech debt is harder to sweep under the rug for years. Those who use MF for polyliths would have to embrace "one platform" arch, the org pivots as one.

Pinning remotes is pretty effective, similar to npm - if I release a breaking change, some take the update - others wait. If you are evergreen and polylith, that's a very ambitious/advanced platform. Considering how other languages (OSGi) implemented similar polylith capabilities- it's immensely complex compared to MF.

At runtime always updating systems need to be designed specifically to leverage that power. These are the types of systems I design - and I can admit that it required a very large shift in thinking. I've been using the technology for 3 years now, it took time to think through all the safety and guards needed to harness MF.

ScriptedAlchemy avatar May 27 '22 06:05 ScriptedAlchemy

If you can't safely implement polylith evergreen. I'd advise against it unless you've got the resources & dev muscle in house to manage such designs. The org needs to be mature enough to handle it - that can be a tall ask. If you're not ready, patterns like LOSA or single spa style are less challenging.

We spent about a year just using MF for ab tests and analytics. Low risk places where we can work observe the behavior without impacting the revenue funnel if it breaks. Then we step it up once we know it's good. We also tend to implement MF only in ways we know we have solved the problems for.

My North Star is as follows

  • Recoil for state management without coupling
  • Generic app shell for all apps/ hosts
  • Sdk for data (recoil atoms)
  • Distributed logging with sentry and error boundaries so we know who failed where and who to page
  • SSR (solved)
  • Self sustaining components (fetch their own data anywhere they go, solved)
  • Proxy re exports, so nobody exposes the module directly - there's always another file where we can add compatibility layers if prop api changes.
  • Versioning (solved)
  • Component builds and federated deploys for all npm packages to s3 as well as npm.
  • BuildHttp webpack experiment when needed to tell webpack to download url contents at buildtime and bundle it with the consumer. Good for pinning & resilience
  • Medusa to gain software topology and remotely control MF

Coupling is a choice of implementation. MFP has one job - link graphs together. For better or worse.

This is a generic problem tho. ESM imports and import maps, url imports. All would have the same challenges.

ScriptedAlchemy avatar May 27 '22 07:05 ScriptedAlchemy