Get environment variable defined in Linux bash to webpack - reactjs

I have checked out tons of SO questions about "environment variables in webpack" using e.g. the DefinePlugin:
new webpack.DefinePlugin({'ENV': JSON.stringify('staging')})
but I cannot for the life of me find a way to inject an environment variable defined in the linux bash shell, instead of using the hard coded staging string
In my production and staging environements I have variables such as $ENV and $API_KEY defined, and I want to use their values in my webpack / ReactJs code.
Edit
I notice, if I run the a webpack command from cli:
$ ENVIRONMENT=staging
$ node_modules/.bin/webpack -p
And in my webpack.config.js file defines
new webpack.DefinePlugin({'ENV': JSON.stringify(process.env.ENVIRONMENT)})
This does not work (ENV is undefined in my JS code),
However, if I run it on the same line, it seems to work - ENVIRONMENT seems to be available in the webpack.config.js file:
$ ENVIRONMENT=staging node_modules/.bin/webpack -p
So I would really like to make this work without having to define the ENVIRONMENT variable on the same line as the webpack command.

In nodejs you can get your environment variables via process.env object. In your case you can do process.env.$ENV and process.env.$API_KEY to get $ENV and $API_KEY env vars respectively.

Stupid me forgot to export the variable in the bash terminal
$ export ENVIRONMENT=staging
$ node_modules/.bin/webpack -p
works fine and, as pointed out, one can then access the ENVIRONMENT variable with process.env.ENVIRONMENT from inside webpack.config.js

Related

.env file variables access after publish

I'm new to react development. I have created .env file(inside root) and got some url for my application. after publish my application to azure my application not getting url values. I have stored it new .env file inside my public folder also. But its not getting values.
.env file(inside root)
REACT_APP_SERVICE_BASE_URL = https://localhost:44385/
REACT_APP_CONFIG_BASE_URL = https://localhost:44354/
js Code
require('dotenv').config()
let SERVICE_BASE_URL = process.env.PUBLIC_URL.REACT_APP_SERVICE_BASE_URL;
Can anyone have an idea to fix my issue. localhost working fine. after publish and change url is not working.
my customers have different Urls. so they need to change with their variables. So I thought if i add .env file inside public folder they can change their Url and use it
Tried this way also. But this also not calling public folder .env Its also taking root folder .env
require('dotenv').config(process.env.PUBLIC_URL+ '/.env')
As mentioned, create-react-app creates a static app, so nothing can be read from environment variables dynamically after build. Instead values from your .env file are copied into the static website during build. Any change afterwards won't change your app.
If you're using Azure App Service: Rather than building the app locally, then publishing the pre-built app bundle, you can instead publish the source of the app and have Azure App Service build the app. This way the customer-specific environment variables (App Settings) are present during build and will be set appropriately in your app.
There's two approaches:
Use a custom build script that you publish with your source code to Azure App Service. The documentation on this isn't great, but it works if you prefer to deploy from git or from a zip file. Kudu is the engine behind both of these deployment scenarios, see the wiki for details. See this example deploy script.
(recommended) Deploy your app using containers, and use an entry point script to replace the environment variables' placeholders with the customer-specific App Service's environment variable values.
Example of #2 (recommended):
Some code examples below. You can also reference this project as a working example of using this approach.
React App code to get the environment variable:
export const getGitHubToken = () => {
if (process.env.NODE_ENV !== 'production') {
if (!process.env.REACT_APP_SERVICE_BASE_URL) throw new Error('Must set env variable $REACT_APP_SERVICE_BASE_URL');
return process.env.REACT_APP_SERVICE_BASE_URL;
}
return '__REACT_APP_SERVICE_BASE_URL__';
};
Entrypoint script run by container:
#!/usr/bin/env bash
# Get environment variables to show up in SSH session
eval $(printenv | sed -n "s/^\([^=]\+\)=\(.*\)$/export \1=\2/p" | sed 's/"/\\\"/g' | sed '/=/s//="/' | sed 's/$/"/' >> /etc/profile)
pushd /home/site/wwwroot/static/js > /dev/null
pattern="main.*.js"
files=( $(compgen -W "$pattern") )
mainFile=$files
sed -i 's|__REACT_APP_SERVICE_BASE_URL__|'"$REACT_APP_SERVICE_BASE_URL"'|g' "$mainFile"
sed -i 's|__REACT_APP_CONFIG_BASE_URL__|'"$REACT_APP_CONFIG_BASE_URL"'|g' "$mainFile"
popd > /dev/null
Dockerfile:
FROM nginx
RUN mkdir -p /home/LogFiles /opt/startup /home/site/wwwroot \
&& echo "root:Docker!" | chpasswd \
&& echo "cd /home" >> /etc/bash.bashrc \
&& apt-get update \
&& apt-get install --yes --no-install-recommends \
openssh-server \
openrc \
yarn \
net-tools \
dnsutils
# init_container.sh is in react app's deploy/startup folder
COPY deploy/startup /opt/startup
COPY build /home/site/wwwroot
RUN chmod -R +x /opt/startup
ENV PORT 8080
ENV SSH_PORT 2222
EXPOSE 2222 8080
ENV WEBSITE_ROLE_INSTANCE_ID localRoleInstance
ENV WEBSITE_INSTANCE_ID localInstance
ENV PATH ${PATH}:/home/site/wwwroot
WORKDIR /home/site/wwwroot
ENTRYPOINT ["/opt/startup/init_container.sh"]
let SERVICE_BASE_URL = process.env.REACT_APP_SERVICE_BASE_URL
As mentioned here https://create-react-app.dev/docs/adding-custom-environment-variables/ .env file is for development purpose.
I suppose you use create-react-app to build your application. In that case the environment variable is injected in your appication at build time.
When you develop locally .env variables are automatically injected to your code.
In the case of a deploy on azure you shoud define your environment variables in that environment and build you application there.

How to hide variables in package.json

I have the following scripts in my package.json file
"docker-build": "docker build -t mouchin/my-image-name .",
"docker-push": "docker push mouchin/my-image-name:latest",
"deploy-server": "ssh root#myserverip 'docker pull mouchin/my-image-name:latest'",
"deploy": "npm run docker-build && npm run docker-push && npm run deploy-server"
Problem is that i want to hide
mouchin/my-image-name and root#myserverip
Using some sort of env, maybe saving my variables in .env.prod , but i dont know if i can read the variables saved there directly into package.json
You can use environment variables in your rpm scripts just as you would if you execute the command on the command line (for example $SSH_HOST). However those variables will need to be set directly in the shell that executes the nom script.
Now in order to get the environment variables from an env file loaded, you have to do so manually. For example using a snippet like this:
if [ ! -f .env ]
then
export $(cat .env | xargs)
fi
Source
To execute this before any other script, you could use the built-in lifecylce scripts of npm.
Perhaps, you also want to change the snippet code to load one or the other .env file in case you have one for production and one for development. You will probably be able to use the environment variable NODE_ENV for this, as it is used in most setups, however this last step really depends on your build setup.

Copy a docker ARG into an Angularjs config file

I have a simple AngularJS application that is built through a Jenkins pipeline and a Docker file. When running the Jenkins job, the environment is set. Then it builds to one of two environments: dev or integration. What I need is a way to get that variable into the angular app.
The docker file uses the environment to build different config settings like:
ARG env
COPY build_config/${env} /opt/some/path...
I need to get that env into one of the controllers. Is there a way to copy env into a controller. I attempted something like the following:
COPY ${env} path/to/angular/file/controller
I have searched and tried different methods but cannot find a solution to work for the Jenkins with Docker pipeline.
You can just use RUN to write a string to a file:
RUN echo "$env" > path/to/angular/file/controller
If you want to append to the file instead of overwritting it, use
RUN echo "$env" >> path/to/angular/file/controller

Docker command not able to pass parameter at runtime to a appConfig.json file

Hi i am new to docker(version 19.03.8) and basically I have an angularjs project(dummyPoject) which contains appConfig.json file with the following path dummyPoject\src\assets\conf\appConfig.json. The json file contains the following variable:
{
"baseUrl": "MAPPED-URL"
}
Basically I want to override the MAPPED-URL properties with the one that i am sending while executing docker command.
Based on the online documentation I found out that it can be passed as environment variable while running the docker command please find below:
docker run -e baseUrl=http://localhost:8081/dummyUrl/ -p 8000:8080 -d --name cms test:1.0
I was expecting that MAPPED-URL will change to http://localhost:8081/dummyUrl/ but it is not the case.
Anything I am missing here please?
By adding -e baseUrl=http://localhost:8081/dummyUrl/ to docker run you have successfully added a environment variable to your docker container. But this value will not magically replace values in your appConfig.json file.
You will need some sort of script that extracts the baseUrl variable from environment and replaces the value in the script. This could be done using a bash script which runs when the container starts and replaces the line "baseUrl": "MAPPED-URL" using the environment variable you added.
Update:
This question inspired me to create a small Node.js package command line package that should help solve your issue. The package is called replace-env
You can add replace-env to your package.json dependencies. You can then run the command as part of your Dockerfile build process, or you can have it modify the file at runtime by customizing your CMD instruction.

Getting container's IP inside a dockerfile

I am running a reactjs app using docker container, and we are using Mock API and UI. I am running those inside a single docker container as 2 separate process. However, in the .env file of the reactjs app the environment variables are mapped to localhost like below :-
REACT_APP_MOCK_API_URL="http://localhost:8080/API"
REACT_APP_MOCK_API_URL_AUTH="http://localhost:8080/API/AUTH"
REACT_APP_MOCK_API_URL_PRESENTATION="http://localhost:8080/API/PRESENTATION"
Since the docker container's IP would be dynamic i need to override it with the dynamic ip that the container will be creating at run time.
May i know the way to do this inside dockerfile ???
PS : I tried assigning the static IP inside the docker file for these environment vars and it works. However, i am not sure how to get the IP dynamically and pass it inside the dockerfile itself .
Please help.
Thanks.
That's intrinsically not something you can directly set up inside the Dockerfile. You usually don't care about the container-internal IP addresses at all: from other containers you should use Docker's internal DNS service, and from outside a container you can access published ports (docker run -p option) via the host's IP address.
In many cases you can glean enough information from HTTP headers to construct valid links within an application. You might be able to set these variables to just e.g. REACT_APP_MOCK_API_URL="/API"; if that's interpreted relative to some other URL in the application then it will inherit the correct host name.
If none of this works, you can use an entrypoint script to set these variables. This might look something like:
#!/bin/sh
if [ -n "$URL_PREFIX" ]; then
# Set these three variables, if they're not already set
: ${REACT_APP_MOCK_API_URL:="${URL_PREFIX}/API"}
: ${REACT_APP_MOCK_API_URL_AUTH:="${URL_PREFIX}/API/AUTH"}
: ${REACT_APP_MOCK_API_URL_PRESENTATION:="${URL_PREFIX}/API/PRESENTATION"}
# Export them to other processes
export REACT_APP_MOCK_API_URL REACT_APP_MOCK_API_URL_AUTH
export REACT_APP_MOCK_API_URL_PRESENTATION
fi
# Launch the main container command
exec "$#"
In your Dockerfile you'd COPY this script in and run it as the ENTRYPOINT
...
COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD [...]
Then when you finally ran the container, you can dynamically inject the URL prefix, including whatever port you choose.
docker run -e URL_PREFIX="http://$(hostname):3456" -p 3456:8080 ...
The entrypoint script will set the other variables based on the URL_PREFIX variable, then run whatever command was set as the CMD in the Dockerfile or was named on the docker run command line. (If you docker run -it ... sh, the entrypoint will run and as its last step launch the interactive shell, which is useful for debugging.)

Resources