Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

There are a few kinds of data sharing we can envision:

Configuration

Shared Config

Today, each MFE loads its own configuration document (either through build-time or runtime config). Much of the config values in these are the same across MFEs, and it’d make sense for them to be defined and made available in one centralized place owned by the shell application.

MFE-specific Config

Some configuration is MFE-specific, and we can imagine that either stays local to the MFE’s code, or gets added to the global configuration document namespaced by the MFE’s unique name. It feels unlikely that other MFEs would need to access it, so I’d likely suggest it stays private to the MFE that owns it.

Global State

The utility of global state partially depends on where we draw the boundaries between MFEs, the shape of each MFE’s data at rest in the client, and how we want to handle client-side cache invalidation of data. MFEs in the same domain are more likely to share information. Account settings and profile, for instance, share detailed user preference data on the client. Course home and courseware should share course structure data, don’t, but are currently in the same MFE and likely shouldn’t.

If a user is switching back and forth between course home and courseware, for instance, or modifying their account settings and checking out the changes in their profile, we could drastically improve performance by caching this data in a global state store for some period of time (a few minutes?)

We’ll also need to build in facilities for evicting data from global state when a user has navigated away beyond the cache expiration.

Implementation

As far as an implementation, I expect the right answer is to use redux, since many MFEs (including those examples shown above) use it for storing data they receive from the server already, our community is familiar with it, and it’s a best in class tool used throughout the industry.

Redux is not a singleton, and multiple stores can co-exist on the page, which would allow MFEs to keep some data ‘private’ as desired, while sharing data we expect to be common with the central data store.

If we want child MFEs to be able to dynamically add reducers to a global redux data store, we’ll need to provide a mechanism to do that, which we don’t have today. There are documented approaches to doing this.

Alternatives

It’s worth noting that API caches (like the LocalforageCache in frontend-platform/auth) play an important role in improving performance here too - given that we make use of BFF (backend for frontend) endpoints in some cases, the API cache would have a miss even though some of the entities are the same.

In many cases, this is going to be advanced performance optimization, which can be more of an art than science, and should likely be performed based on user activity metrics which we may not have today.

Eventing

It’s difficult to imagine use cases today where we’ll need an eventing system to publish and subscribe to messages. Many things that may seem like events may be better suited to an imperative API exposed by the shell, or through frontend-platform.

For instance, one thing that comes to mind is an MFE telling the shell to switch to a different header or footer. The advantage of eventing is that we don’t need to know or care who the event’s consumers are; in this case, we very much want to tell a specific entity (the header) to change. That’s not an ideal use case for events.

Put another way, we should be careful to use events for sharing information, not making requests.

i18n Messages

As MFEs load, they need to get their localized messages into the internationalization system so they’re available to be used. We can imagine that dynamically loaded components may export