-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
-
Our company adopted ModernJS because we are going with a new MFE experience for our new applications as it fits how we want our integrators to use pieces of what we offer.
The issue is that we are a big company, which for fun is listed on the list of the companies using Module Federation, but our client team doesn't control our own deployment using UKS/AWS/pods. The deployment team implemented a build once - deploy many pipeline that is not how react applications work. Note, they are used to services not applications that are able to do this. Normally react is build many - deploy many or in other words if you change your ENV or deployment line, you have to rebuild react to update.
Since ModernJS has a node server, it has the ability to use react router and page.data.ts with useDataLoader to read the new ENV when deploying/serving node to pass the environment down to the pages.
Of course this doesn't work for module federation, even if you share the route page. It just never hits the loader.
I am just looking for a way to fix this so that the node env can be added to the single build of react/modernjs. Something easier than basically doing a string replace before running the node server on the already built code or at least a way to do that programmatically.
Feel free to laugh now and ask me if I am serious but unfortunately I am but I still don't mind being laughed at.
After laughing, is there anyway I am missing to do this runtime ENV from node to the shared components in the provider?
Thanks.
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment 4 replies
-
@bmoellers Sorry for the late reply to this question. I'm not sure I understand what you mean. If your question is about accessing different environments at runtime, you can build all environments into a JSON file, and then use this file to retrieve information about the target environment.
Beta Was this translation helpful? Give feedback.
All reactions
-
That is true if you are serving the main application. However you cannot for how we are using Modern JS as a host for MFE (micro frontends). So what we need is not to have our MFE tenants to have to worry about loading the environment variables but have the MFE do that.
So if the MFE is hosted at localhost:3000 and the consumer is running at localhost:3100.
So if we use a script tag to load the JSON, <script src="./config.json /> it needs to load from localhost:3000 (<script src="localhost:3000/config.json />) but since it is actually running in the consumer it is loading from <script src="localhost:3100/config.json />.
To fix this we can add an ENV variable (<script src="{process.ENV.BASE_URL/config.json} />) which will work in this case as it is a single build for local development.
But that doesn't extend to multiple deployments at least when the leave the pod. You cannot have an external localhost running on an externally exposed URL because that localhost would try to load on the computer it is running not refer to internal pod localhost. That process.ENV.BASE_URL for the test line is different from the external test line for tenants, and different again for production. However that is replaced at build time not run time. So we have the same problem that we tried to solve using a script.
The same happens for a fetch. You locally you can point the fetch to localhost:3000/api/config. But if you again have three lines, you have to point the line1/api/config, line2/api/config, so that self reference has to change but cannot depend on the config itself. So again you need to fetch(${process.ENV.HOST_URL/api/config.json}) but that requires the config.json to load correctly.
The configurations are not the same on each line either so you cannot have a single config file. I definitely agree you can overwrite a config.json, as we use HELM charts on the deployment and there is definitely a way to do this. However it is that one last issue that you have to point to the host and not the consumer. Modern JS has an API mechanism that definitely will point to the consumer and scripts also do the same thing.
I even tried using dynamic imports like const jsonEnv = await import('../../public/static/env.json'); However cannot get rspack in Modern JS to make it an external file that I can overwrite instead of a chunked file. I think this might work if I can get the rspack things working correctly though it may also have the same problem of trying to load from the consumer not the host but hopeful.
Beta Was this translation helpful? Give feedback.
All reactions
-
make a shared module or remote module where the env vars are exported, then one can import them.
process.env is a compile time string replace in your source (DefinePlugin) to provide them to other files will require some way to transfer them, either via js as a exposed module from host or as a shared module that you can then use something like import vars from 'host-env-vars" etc
Beta Was this translation helpful? Give feedback.
All reactions
-
There are many ways to solve this however the main thing was the self reference. Because it was an MFE running another application. The key for us to solve this was:
const publicPath = new URL(__webpack_public_path__);
Once you have a public path from web pack, it becomes easier. In Modern JS that allows you to use the NodeJS API:
const publicPath = new URL(__webpack_public_path__);
const response = await fetch(`${publicPath.origin}/api/config`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
You can also do a dynamic import, use the web pack external file, an external JSON asset, etc... I did most of those things but they all failed until I found __webpack_public_path__ (which I should have remembered but since was mainly doing full apps it was never useful).
In my case the API is easier as it still deploys with the same MFE app, but also has the ability to be configured if I want to pass in parameters. The static JSON, dynamic imports, ... were more static with the data but could definitely still work.
Hope that explains how we actually solved this issue.
It does rely on a Node Server back end but since we already had that, it made it easier. Solving it for React itself would probably be better as one of the static methods where you could use a script to replace files that are external JSON.
Beta Was this translation helpful? Give feedback.
All reactions
-
Yeah, that works too. Usually, I use __webpack_require__.federation.instance.name, then search the __FEDERATION__ global where I can find the absolute URL of that name in the remotes list of one of the other instances.
Beta Was this translation helpful? Give feedback.