4

The question about injecting Environment Variables after bundling with Webpack is already asked and answered.

The answer is always based on loading the updated Environment Variables inside the index.html file.

But when using Webpack Module Federation, we are exposing only a component.js file, so how can I bundle the source during the docker build phase, but read the Environment Variables during the serving phase (when running our bundle as a pod inside k8s, for example).

baruchiro
  • 5,088
  • 5
  • 44
  • 66

3 Answers3

2

Currently, we are combining the webpack.EnvironmentPlugin with Docker.

In webpack.config.js, we are substituting the Environment Variables with a special string:

plugins: [
    new EnvironmentPlugin({
        MY_CUSTOM_ENV_VAR: '{{MY_CUSTOM_ENV_VAR}}',
        ANOTHER_ENV_VAR: '{{ANOTHER_ENV_VAR}}',
    }),
],

It means, during the build time, if there are no such Environment Variables, the bundle will include the strings '{{MY_CUSTOM_ENV_VAR}}' and '{{MY_CUSTOM_ENV_VAR}}'.

Now, to replace those variables on container starts, we are adding a substitute to the RUN command:

CMD sed -i "s@{{MY_CUSTOM_ENV_VAR}}@${MY_CUSTOM_ENV_VAR}@g" /usr/share/nginx/html/*.bundle*.js \
    && sed -i "s@{{ANOTHER_ENV_VAR}}@${ANOTHER_ENV_VAR}@g" /usr/share/nginx/html/*.bundle*.js \
    && nginx -g "daemon off;"

(It will replace the string {{MY_CUSTOM_ENV_VAR}} with the value of ${MY_CUSTOM_ENV_VAR} on the bundle files: /usr/share/nginx/html/*.bundle*.js (nginx))

baruchiro
  • 5,088
  • 5
  • 44
  • 66
0

I'm strugling with the same issue... And I can only think of using a convention in the container for handling this problem.

All micro-frontends could potentially expose their environment variables in ./assets/env.template.js (then finally ./assets/env.js) with ${MY_ENVIRONMENT_VARIABLE} as placeholders.

This env.template.js will be an autoexecuting javascript function that will just introduce the environment variable values as global properties of the window (see below the example).

env.template.js

(function (window) {
  window.env = window.env || {};
  window['env']['clientId'] = '${CLIENT_ID}';
  window['env']['baseUrl'] = '${BASE_URL}'
})(this);

When creating the docker image a final asset env.js will be generated that will substitute the environment variables. For example creating the docker nginx image with:

CMD ["/bin/sh", "-c", "envsubst < /usr/share/nginx/html/assets/env.template.js > /usr/share/nginx/html/assets/env.js && exec nginx -g 'daemon off;'"]

The container when loading the remotes could try to dynamically load their env.js files exposed in assets.

The normal angular injected environment would get the values from the window.env the values.

Jon
  • 9
  • 4
  • Finally I ended with a similar solution but a little more elegant because we use dynamic module federation. Our container loads the microfrontends based on a configuration that describes their remote entries and available modules. Before solving this problem we just had 'routing' module type (used by the root routing module to build the routes) and 'other' module type (used for other types of plugin modules like dashboard widgets,...). In order to solve the problem we added a new startup module type that will be loaded at startup and this one will be the responsible of loading the env.js – Jon Aug 07 '22 at 15:54
-1

In the webpack.config

const webpack = require('webpack');       
require('dotenv').config({ path: './.env' }); 

Then in the plugin modules part add this

new webpack.DefinePlugin({
  "process.env": JSON.stringify(process.env);
}),

This will bring to code all Environment Variables from the machine.

Another improvement is required this way, with this you can create files like .env.development or .env.production

module.exports = (env, args) => {
    require("dotenv").config({ path: `./.env.${args.mode}` });

If you want to pass just the env vars you define in the .env files just change the require to this:

const dotenv = require("dotenv").config({ path: ./.env.${args.mode}` }); 

and the definePlugin to this:

new webpack.DefinePlugin({ "process.env": JSON.stringify(dotenv.parsed), }),
baruchiro
  • 5,088
  • 5
  • 44
  • 66
  • But please note, all those solutions are available during the `webpack` command- the "build" time. Now let's say I already bundled my code, and I created a Docker Image with it. How can I launch the container with some Env Vars that will be used inside the bundle? – baruchiro Jan 06 '22 at 06:44
  • you can build the application inside a Dockerfile, just use entry point commands – Vitor de oliveira Jan 12 '22 at 11:44
  • But then the load takes time – baruchiro Jan 13 '22 at 12:35
  • 1
    I don't think this really answers the question. Getting environment variables into a docker container at build time is a solved problem. The question is about runtime, which does not have widely-understood solutions. – Daven Quinn Jan 25 '22 at 06:12