admin管理员组文章数量:1130349
I have set up a container app that consumes several remote apps. The issue is that I need the remote urls to be dynamic based on what environment they are in (Test, Dev, QA). As you can see my vehicle remote url is hardcoded pointing to dev. I need this URL to be updated based on the environment. I want to use env variables if possible. I can't find a clear answer and was hoping someone would have some suggestions.
const devConfig = {
mode: "development",
devServer: {
port: 3000,
historyApiFallback: true,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
filename: "remoteEntry.js",
remotes: {
vehicle:
"vehicle@.js",
}
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
],
};
I have set up a container app that consumes several remote apps. The issue is that I need the remote urls to be dynamic based on what environment they are in (Test, Dev, QA). As you can see my vehicle remote url is hardcoded pointing to dev. I need this URL to be updated based on the environment. I want to use env variables if possible. I can't find a clear answer and was hoping someone would have some suggestions.
const devConfig = {
mode: "development",
devServer: {
port: 3000,
historyApiFallback: true,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
filename: "remoteEntry.js",
remotes: {
vehicle:
"vehicle@https://vehicle-mf-dev./remoteEntry.js",
}
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
],
};
Share
Improve this question
edited Sep 2, 2022 at 16:16
codythedev
asked Aug 31, 2022 at 21:59
codythedevcodythedev
1111 gold badge1 silver badge4 bronze badges
4
-
1
can you access
process.envobject in this file ? try console.log(process.env) in this file. – Faizan Ul Haq Commented Sep 2, 2022 at 16:21 - The documentation suggests using promise based remotes webpack.js/concepts/module-federation/… Haven't tried though. I use dynamic loading and discovery service which return the remote urls, which you can mock in dev environment. – Art Bauer Commented Sep 2, 2022 at 16:22
- Hi @ArtBauer,Could you share the detail of "dynamic loading and discovery service" way for this? – WW00WW Commented Jun 17, 2024 at 10:55
- As for today, my discovery service is just a json file "modules.json" with list of "apps" containing urls pointing to apps deployments (but you can obtain it from the server). When building the application I copy this file to the output (/dist) folder. When the application starts it requests "modules.json" and use loadComponent function described here webpack.js/concepts/module-federation/… – Art Bauer Commented Jul 8, 2024 at 14:45
2 Answers
Reset to default 3You should use environment variables. Then, just replace your environment with your environment variable. It's to say:
1- Create an environment variable. You can use a .env file or create an environment variable. For instance, in UNIX systems you can do export API=https://vehicle-mf-dev..
More info: https://nodejs.dev/en/learn/how-to-read-environment-variables-from-nodejs/
2- Then you can use this environment variable in your code:
const devConfig = {
mode: "development",
devServer: {
port: 3000,
historyApiFallback: true,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
filename: "remoteEntry.js",
remotes: {
vehicle:
`vehicle@${process.env.API}/remoteEntry.js`,
}
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
],
};
I encountered a similar issue that needed a fast fix for a client that had multiple customers with different domains for each customer so I had to get the webpack module federation to use dynamic remotes, I used relative paths for the remotes:
name: 'container',
//The value is constructed as follows:
// - the part before the '@' is the name mentioned in the remote ModuleFederationPlugin
// - the part after the '@' is the URL of the remote entry file
// WARNING: never name the remote project as a class name, it will cause a conflict
remotes: {
media: `media@/media/latest/remoteEntry.js`,
},
In the browser, relative paths are resolved to the website's root path, which is perfect in this case. because the domain was the only difference in my case between the customers.
if you need other mon variables between the micro frontends I found out that the go-to solution is to use a relative request in index.js to /config.json and inject the variables into the window object before calling the bootstrap file something like:
// main.js or index.js in the host app
async function loadConfig() {
try {
const response = await fetch('/config.json');
const config = await response.json();
window.__sharedConfig__ = config;
} catch (error) {
console.error('Error loading config.json:', error);
}
}
(async () => {
await loadConfig();
await import('./bootstrap');
})();
NOTE: didn't test the snippet of the code loadConfig above take it more as an example of what suppose to be done.
if you need to template other env vars in the webpack config file after the bundle (I don't remend this solution it feels 'hacky' for me; but didn't find alternatives for templating vars in the webpack config):
- the bash script (you need to specify each env var in the envsubst or it will break the script); in the next example it will replace the string '$SOME_VAR' in all the bundle files with the desired value:
#!/bin/sh
# Replace the placeholders in the JavaScript files with the actual values
if [ -n "$SOME_VAR" ]; then
export SOME_VAR
for file in /usr/share/nginx/html/container/latest/*.js; do
envsubst "SOME_VAR" <"$file" >"$file.tmp"
mv "$file.tmp" "$file"
done
fi
# Start Nginx
nginx -g "daemon off;"
- the Dockerfile that I used (if you don't use the entrypoint solution ment out the last 3 steps: COPY, RUN chmod adn the ENTRYPOINT)
FROM node:18-alpine3.17 as base
WORKDIR /usr/src/app
COPY yarn.lock tsconfig.json package.json nx.json lerna.json ./
# copy package.json for install dependencies
COPY ./packages/eslint-config/package.json ./packages/eslint-config/package.json
COPY ./web/container/package.json ./web/container/package.json
# install dependencies
# TODO: need to move all relevat dependencies from devDependencies to dependencies
# better even create package for webpack container configuration
RUN yarn install --frozen-lockfile
# --production
# copy source code
COPY ./packages/eslint-config ./packages/eslint-config
COPY ./web/container ./web/container
# build container service
RUN yarn build --scope=@premade/container-host
# Use the official Nginx image as the base
FROM nginx:stable-alpine3.17
EXPOSE 80
# Copy your built frontend assets
COPY --from=base /usr/src/app/web/container/build /usr/share/nginx/html/container/latest
# Copy your Nginx configuration
COPY --from=base /usr/src/app/web/container/config/nginx.conf /etc/nginx/conf.d/default.conf
# TODO: seems there a more popular way to do this
# /config.json request on bootstrap to relative path
# to serve mon variables or env variables
# Copy your entrypoint.sh script to handle the environment variables
COPY ./web/container/scripts/entrypoint.sh /usr/local/bin/entrypoint.sh
# Set the proper permissions for the entrypoint.sh script
RUN chmod +x /usr/local/bin/entrypoint.sh
# Set the entrypoint.sh script as the entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
used Lerna monorepo in the docker file I mention again I didn't use the entrypoint eventually and went with the relative path solution for some reason when you try to template remote paths it duplicates the domain in the remote path request, but it worked like a charm for other env vars in the webpack config.
I have set up a container app that consumes several remote apps. The issue is that I need the remote urls to be dynamic based on what environment they are in (Test, Dev, QA). As you can see my vehicle remote url is hardcoded pointing to dev. I need this URL to be updated based on the environment. I want to use env variables if possible. I can't find a clear answer and was hoping someone would have some suggestions.
const devConfig = {
mode: "development",
devServer: {
port: 3000,
historyApiFallback: true,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
filename: "remoteEntry.js",
remotes: {
vehicle:
"vehicle@.js",
}
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
],
};
I have set up a container app that consumes several remote apps. The issue is that I need the remote urls to be dynamic based on what environment they are in (Test, Dev, QA). As you can see my vehicle remote url is hardcoded pointing to dev. I need this URL to be updated based on the environment. I want to use env variables if possible. I can't find a clear answer and was hoping someone would have some suggestions.
const devConfig = {
mode: "development",
devServer: {
port: 3000,
historyApiFallback: true,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
filename: "remoteEntry.js",
remotes: {
vehicle:
"vehicle@https://vehicle-mf-dev./remoteEntry.js",
}
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
],
};
Share
Improve this question
edited Sep 2, 2022 at 16:16
codythedev
asked Aug 31, 2022 at 21:59
codythedevcodythedev
1111 gold badge1 silver badge4 bronze badges
4
-
1
can you access
process.envobject in this file ? try console.log(process.env) in this file. – Faizan Ul Haq Commented Sep 2, 2022 at 16:21 - The documentation suggests using promise based remotes webpack.js/concepts/module-federation/… Haven't tried though. I use dynamic loading and discovery service which return the remote urls, which you can mock in dev environment. – Art Bauer Commented Sep 2, 2022 at 16:22
- Hi @ArtBauer,Could you share the detail of "dynamic loading and discovery service" way for this? – WW00WW Commented Jun 17, 2024 at 10:55
- As for today, my discovery service is just a json file "modules.json" with list of "apps" containing urls pointing to apps deployments (but you can obtain it from the server). When building the application I copy this file to the output (/dist) folder. When the application starts it requests "modules.json" and use loadComponent function described here webpack.js/concepts/module-federation/… – Art Bauer Commented Jul 8, 2024 at 14:45
2 Answers
Reset to default 3You should use environment variables. Then, just replace your environment with your environment variable. It's to say:
1- Create an environment variable. You can use a .env file or create an environment variable. For instance, in UNIX systems you can do export API=https://vehicle-mf-dev..
More info: https://nodejs.dev/en/learn/how-to-read-environment-variables-from-nodejs/
2- Then you can use this environment variable in your code:
const devConfig = {
mode: "development",
devServer: {
port: 3000,
historyApiFallback: true,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
filename: "remoteEntry.js",
remotes: {
vehicle:
`vehicle@${process.env.API}/remoteEntry.js`,
}
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
],
};
I encountered a similar issue that needed a fast fix for a client that had multiple customers with different domains for each customer so I had to get the webpack module federation to use dynamic remotes, I used relative paths for the remotes:
name: 'container',
//The value is constructed as follows:
// - the part before the '@' is the name mentioned in the remote ModuleFederationPlugin
// - the part after the '@' is the URL of the remote entry file
// WARNING: never name the remote project as a class name, it will cause a conflict
remotes: {
media: `media@/media/latest/remoteEntry.js`,
},
In the browser, relative paths are resolved to the website's root path, which is perfect in this case. because the domain was the only difference in my case between the customers.
if you need other mon variables between the micro frontends I found out that the go-to solution is to use a relative request in index.js to /config.json and inject the variables into the window object before calling the bootstrap file something like:
// main.js or index.js in the host app
async function loadConfig() {
try {
const response = await fetch('/config.json');
const config = await response.json();
window.__sharedConfig__ = config;
} catch (error) {
console.error('Error loading config.json:', error);
}
}
(async () => {
await loadConfig();
await import('./bootstrap');
})();
NOTE: didn't test the snippet of the code loadConfig above take it more as an example of what suppose to be done.
if you need to template other env vars in the webpack config file after the bundle (I don't remend this solution it feels 'hacky' for me; but didn't find alternatives for templating vars in the webpack config):
- the bash script (you need to specify each env var in the envsubst or it will break the script); in the next example it will replace the string '$SOME_VAR' in all the bundle files with the desired value:
#!/bin/sh
# Replace the placeholders in the JavaScript files with the actual values
if [ -n "$SOME_VAR" ]; then
export SOME_VAR
for file in /usr/share/nginx/html/container/latest/*.js; do
envsubst "SOME_VAR" <"$file" >"$file.tmp"
mv "$file.tmp" "$file"
done
fi
# Start Nginx
nginx -g "daemon off;"
- the Dockerfile that I used (if you don't use the entrypoint solution ment out the last 3 steps: COPY, RUN chmod adn the ENTRYPOINT)
FROM node:18-alpine3.17 as base
WORKDIR /usr/src/app
COPY yarn.lock tsconfig.json package.json nx.json lerna.json ./
# copy package.json for install dependencies
COPY ./packages/eslint-config/package.json ./packages/eslint-config/package.json
COPY ./web/container/package.json ./web/container/package.json
# install dependencies
# TODO: need to move all relevat dependencies from devDependencies to dependencies
# better even create package for webpack container configuration
RUN yarn install --frozen-lockfile
# --production
# copy source code
COPY ./packages/eslint-config ./packages/eslint-config
COPY ./web/container ./web/container
# build container service
RUN yarn build --scope=@premade/container-host
# Use the official Nginx image as the base
FROM nginx:stable-alpine3.17
EXPOSE 80
# Copy your built frontend assets
COPY --from=base /usr/src/app/web/container/build /usr/share/nginx/html/container/latest
# Copy your Nginx configuration
COPY --from=base /usr/src/app/web/container/config/nginx.conf /etc/nginx/conf.d/default.conf
# TODO: seems there a more popular way to do this
# /config.json request on bootstrap to relative path
# to serve mon variables or env variables
# Copy your entrypoint.sh script to handle the environment variables
COPY ./web/container/scripts/entrypoint.sh /usr/local/bin/entrypoint.sh
# Set the proper permissions for the entrypoint.sh script
RUN chmod +x /usr/local/bin/entrypoint.sh
# Set the entrypoint.sh script as the entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
used Lerna monorepo in the docker file I mention again I didn't use the entrypoint eventually and went with the relative path solution for some reason when you try to template remote paths it duplicates the domain in the remote path request, but it worked like a charm for other env vars in the webpack config.
本文标签:
版权声明:本文标题:javascript - How can I make module federation remote URLs dynamic based on the environment (Test, QA, Dev)? - Stack Overflow 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://it.en369.cn/questions/1743854968a2041395.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论