Create an extensible architecture with React - reactjs

My team is creating the administration panel of a CMS using React, Typescript, TSX and Webpack. Each page of the administration panel has been created as a React component, and each page contains many other child components (one for each section).
The CMS distribution currently includes a bundled version of the javascript needed to run the web app, but not the original TSX files.
Now, we would like to make it possible to the developers using our CMS to extend the web app by
1) Injecting additional sections into the UI using a "slot-fill" approach
2) Possibly even overriding the existing sections rendering a different component in the same place.
<div>
<SidebarComponent />
<Section1Component />
<Section2Component />
// How to inject a possible PluginComponent here?
</div>
From the research we've conducted so far, there seem to be no "official" way to do this, so I'm wondering what would be the best approach in this case.

I am facing the same issue where I need a component from a plugin to interact with a component from another plugin with a hook system. I have a created a small codesanbox with the same approach adapted to your need.
Basically the approach is to create a injectedComponents.js at the root of your plugin that specifies in which plugin and area your component needs to be injected.
Here is ademo

single-spa has some good options in order to achieve this.
Please see if it can be help for you.
Microfrontends
Parcels

I am late to this but
Just create a utility class with registry function, and register each component to the registry (just dictionary of key value pair, where key is a constant and Value is the component). T
Then when you display a component in your base app, get it from the registry using a key. Then once you publish this whole base app as package ( make sure to export the utility registry). A user can register a component with the same name and override the default component.

For communication between totally independant components, you can use and EventEmitter

Related

react with webpack federation plugin: why load react twice?

probably I have a conceptual error regarding Module Federation. What I am trying to do is create a "shared project" (reactcore) that loads react, react-dom, MUI, etc, but not any specific UI. and the other UI's (diverse widgets) that I want to load will reuse the react and other dependencies offered by the core (use the core just as a library provider).
what I got is that if load both scripts (mpreactcore and mpwidgets, the one with the UI) it works, but react and react-core are being loaded TWICE.
[![screenshot][1]][1]
[1]: https://i.stack.imgur.com/rXEYB.png
I am wondering if I am trying to use Module Federation the wrong way. perhaps it is mandatory that the "core" should be a "shell" and all the other widgets should be injected in the shell, for example, passing a parameter when creating a single App component? my approach is due to the fact that my widgets are loosely coupled, more like a library of utilitarian widgets rather than a massive unified UI.
thanks for your recommendations.

Create an Product Page editor

What we want to do:
We have two projects:
A consumer focused frontend
A business focused dashboard
The frontend uses cool custom styling, while the dashboard is rather boring. The idea is that you can edit and create objects in the dashboard and then preview them in the styling of the frontend (imagine setting up an amazon product and then previewing it as the product page). Ideally we would also like to offer live editing, meaning you see the proper rendered product page and you can edit the information live.
Our Setup
Two separate repositories
Both use React + Tailwind
There are not many custom CSS classes as everything is styled via tailwind classes in the code
What would be the best solution?
I have a couple of solutions, that might work with more or less success (e.g. sharing components via bit.dev). Did someone built something similar or could recommend some best practices?
Depends on what is the best solution for you. What is best for you, might not be the best for me, or the other way around.
Bit is a way to share components. Components are isolated pieces of functionality (UI, Hooks, Themes, whatever) That can be used and consumed across several projects.
You could totally have a Bit workspace, where you design, create and edit your components, export them once finished, and consume them in both your repositories.
bit new react my-shared-components-workspace --default-scope LeonardCompany.LeonardRemoteScope
cd my-shared-components-workspace
bit create react shared-button
# edit your button
bit tag -m "initial tag" shared-button
bit export shared-button
In your repos:
npm install #bit/LeonardCompany.LeonardRemoteScope.shared-button
Want to update the button? Edit it again in your workspace, export, and update the projects. Ultimately, those projects could be App components too.
Let me know if it helped.

How to properly pass configuration to a React Component

I have created a React package that I've uploaded to an NPM repo for being consumed for React Apps. What I want to achieve is to be able to set up certain parameters when consuming my component. Let's suppose that my package calls an API. This package is being used for 2 apps, App A and App B. App A needs that the component calls an url whilst App B is going to call another url. Is there any particular way to achieve this (like Axios does ie).
The main thing, I think, is that my package has a lot of components and this configuration can be used in any of them, so what I want to do is not to pass it to the root component, just having it available all the time. I have read about Context API but I am not sure if this is the correct approach or if there is even an easier way since these values are not going to be updated once the application started, these values will remain static.
Please let me know if my question is unclear.
Thanks.
what you can do is to follow the rule "build oncedeploy everywhere"...you can put a app-config.json that contain your app config file in your public folder... in your main component you fetch that file ...
a second approach is to use .env file and use it everywhere in your app like this :process.env.REACT_APP_API_URL...check this out https://create-react-app.dev/docs/adding-custom-environment-variables/
Now there is an alternative to dotenv in React for configuration: wj-config. Currently in beta, the v2 will provide a very robust set of configurations. The ReadMe for this package is very extensive and explains how to use it in React in detail.
I am unsure if all you need is a configuration method or not. In any case, I would still recommend that you give it a shot. You may also read this blog post that explains this new configuration package.

React context between microfrontends

TLDR; How to use a single context between react micro frontends?
The application is divided into multiple Microfrontends or react apps. Each of these is running on a different port. A container is hosting other Micrfrontends. Each one is a separate react app and it is a runtime integration. (I have used martinfowler example to implement micro frontend)
Currently passing some data via URL and browser storage (localStorage/cookies) to other Microfrontends.
I need to pass the data across these react apps (MFEs) using React Context.
I have defined ReactContext Provider in Container (ReactApp1) and stored value (say color=black). To access this color inside the lower level Microfrontend (ReactApp2) we need the context to be available from any micro frontend. How to make it available?
(NOTE: I don't want to use localStorage or cookies for global data sharing)
<Container>
<LowerLevelMFE1/>
<LowerLevelMFE2/>
...
</Container>
Webpack 5's Module Federation & ModuleFederationPlugin is the best way I've found to achieve this architectural pattern.
In essence you create a "host" application that wraps the React.context around a "remote" component. This "remote" is actually another component in a standalone application that is being exposed as a remote through its webpack config file. In this 2nd application you would consume the context as normal using React.useContext.
You can find a full example of this setup here on github.
A few things to note:
Both applications will need to consume this Context's source code so moving it into its own package is preferred.
Your Context consuming application will still need, what I call in MFEs, "developer scaffolding". In this case that would be a simple component that wraps your <ContextConsumer /> in a <ContextProvider /> that you are importing from your shared Context package I mentioned in 1.
Remember this app with scaffolding is only exposing the <ContextConsumer /> which you need to make sure to specify in the webpack config.
I think sharing context between Micro-frontends is an anti-pattern and should be avoided if you can. If you use context to share data, you will automatically couple the MFes that depend on the context, eliminating the benefits of independent deployments by introducing coordination and a dependency.
My advice is that each micro-frontend loads the data they need and if there is communication need it, you need an api or a contract to handle this communication.
I think if you need that type of comunication between the mfe's then they are splited wrong.
As Ruben says, is an anti pattern.

How to render a React app in a React app (nested React apps)

So the question is if it is possible to split a React app into two different separate apps hosted on two different hosts, where the app A is a kind of a frame which controls the app B and C in the future. I have a problem, where I would like to make a common fundament for both apps (the A app) and then load two other as a content of it. It would be as if I had lazy loading with a bundle fetched from a different place. I was thinking about three main possibilities:
Iframe
Single SPA project from github
using ReactDOM.render method
I am not sure if it is possible at all, beacuse there still may be a problem with React Router - does the inside app have access to manipulate the browser routing?
It is quite possible to split your react Application into multiple smaller react applications.
Suppose you have a react application such as an e-commerce platform . You can choose to write the cart Page using a separate react-App and the products page using another separate react app and integrate them together using Module Federation Plugin webpack/lib/container/ModuleFederationPlugin.
A good reason to do something like that would be to develop different parts of your application in isolation ..and they can be taken care by different teams altogether.
There is a udemy course that teaches you exactly that. Very much recommended. You can make react dependency as singleton to avoid several installs of react.
All 3 of these options you've stated are valid and can be used to share components but there are few disadvantages to each one, for example- iFrames makes it hard to create responsiveness, ReactDOM splits your app so that the different parts won't have the same global scope...
Module-Federation is the best and most efficient way to share remote components that i know of, here is a github link to a basic project.
The MF plugin makes use of webpack's abilities, which means that the shared components are being consumed as runtime objects of the app's scope, rather then as a promise of an iframe.
NOTE: Debugging and updating a Module Federation project is a much deeper task then debugging a create-react-app application, you'll need to share dependencies correctly and remember to update desired changes at all the right places all the time.
This is not possible. Each react app can only have a single package.json in the hierarchy. if you nest it, the app will fail and say you have several installs of react. what you should do is think more react minded and objecty. You can have a folder for common components to share inside src/. You can also have src/A which is one "app". src/B which is another.
What you described in your question is exactly what you should do, just dont think of it as a react app separation, rather a seperation of component and app inside the src folder. App A can be comprised of components from /components as well as App B.

Resources