How to set .env for react app deployed with azure devops pipeline on app service - reactjs

I developed a pipeline with CI/CD on azure Devops for deploying a React app on Azure web app service. Locally I'm using a .env file and this file is on .gitignore. I want to know how can i set the .env for reading it on production.

You can check the documentation below:
https://create-react-app.dev/docs/adding-custom-environment-variables/#adding-development-environment-variables-in-env
.env files should be checked into source control (with the exclusion of .env*.local ).
If you don't want to check in the .env files to DevOps, you could add the variables in the pipeline variables:
In addition, you can refer to the following case for more suggestions:
How to use environment variables in React app hosted in Azure

Many of the proposed solutions related to this issue may not work but I solved it the following way. However, first let me explain why other solutions may not (should not) work (please correct me if I am wrong)
Adding pipeline variables (even though they are environment variables) should not work since a react app is run on the client side and there is no server side code that can inject environment variables to the react app.
Installing environment variable task on the classic pipeline should not work for the same reason.
Adding to Application Settings in azure app service should not work for the same reason.
Having .env or .env.development or .env.production file in a git repo should not be a good practice as it may compromise api keys and other sensitive information.
So here is my solution -
Step1: Add all those .env files to azure devops library as secure files. You can download these secure files in the build machine using a DownloadSecureFile#1 pipeline task (yml). This way we are making sure the correct .env file is provided in the build machine before the task yarn build --mode development in the pipeline.
Step2:
Add the following task in your azure yml pipeline in appropriate place. I have created a github repo https://github.com/mail4hafij/react-yarn-azure-pipeline if you want to see a complete example.
# Download secure file from azure library
- task: DownloadSecureFile#1
inputs:
secureFile: '.env.development'
# Copy the .env file
- task: CopyFiles#2
inputs:
sourceFolder: '$(Agent.TempDirectory)'
contents: '**/*.env.development'
targetFolder: '$(YOUR_DEFINED_PROJECT_ROOT_FOLDER_VARIABLE)'
cleanTargetFolder: false
Keep note, secure files can't be edited but you can always re-upload.

Related

Azure DevOps - React App - Set Environment Variables in Release Pipeline

We have a React app in AzureDevOps. We build it using npm install/npm run build and then upload the zip file. From there we'll do a release to multiple stages/environments. Due to SOX compliance we're trying to maintain a single build/artifact no matter what the environment.
What I'm trying to do is be able to set the environment variables during the release pipeline. For instance, be able to substitute the value of something like process.env.REACT_APP_CONFIG_VALUE
I've tried setting that in the Pipeline variables during the release but it does not seem to work. Is this possible or do I have to use a json config of some sort instead of using process.env?
Thanks
You could not achieve this by setting pipeline variables during the release.
Suggest you could use RegEx Match & Replace extension task to achieve this. Use this site to convert the regular expression: Regex Generator
Here is an example:
this._baseUrl = process.env.REACT_APP_CONFIG_VALUE;
This extension task will use regular expressions to match fields in the file.
Checking from published js.
This is how I did it -
Step1: Add all those files (.env .env.development .env.production) to azure devops library as secure files. We can download these secure files in the build machine using a DownloadSecureFile#1 pipeline task (yml). This way we are making sure the correct .env file is provided in the build machine before the task yarn build --mode development in the pipeline.
Step2: Add the following task in your azure yml pipeline in appropriate place. I have created a github repo https://github.com/mail4hafij/react-yarn-azure-pipeline if you want to see a complete example.
# Download secure file from azure library
- task: DownloadSecureFile#1
inputs:
secureFile: '.env.development'
# Copy the .env file
- task: CopyFiles#2
inputs:
sourceFolder: '$(Agent.TempDirectory)'
contents: '**/*.env.development'
targetFolder: '$(YOUR_DEFINED_PROJECT_ROOT_FOLDER_VARIABLE)'
cleanTargetFolder: false
Keep note, secure files can't be edited but you can always re-upload.

Firebase + Next.js serverless, on GCP - How to manage staging, production + local

I'm using React with next.js and Google Cloud functions to serve the app. I also use firebase. I'm looking for the best way to automatically configure the staging and production configuration for the 3 environments.
Production: Uses production credentials
Staging: Uses staging credentials
Local: Also uses staging credentials
I have two Firebase projects and currently switch between the configuration using the firebase.js file in my app. I swap out the config object, then deploy. I want to be able to run the app locally, and both on staging and production without changing anything on deploy as it leads to errors.
The issue for me is setting different environment variables for the two cloud projects...I can read cloud environment variables I set up there, but only in the cloud functions environment, not in the client-facing app, which is where I am currently swapping the configuration.
I can see this being solved by:
Google Cloud Platform environment variables (but I have tried and failed to read them from the client). Maybe I change the next.js config to read something up in the cloud when running, instead of doing the config change at deploy?
Local nextjs environment configuration but this doesn't know anything about the two different servers (only dev vs prod which don't match up exactly with local and cloud)
React dotenv configuration (same as the point above)
webpack / npm configuration that swaps the config when compiling
Swapping env based on firebase use [environment] on the command line at deploy time
Points #1 and #5 seem the most likely candidates for automatic and seamless deployment but I can't figure out how to read the GCP config variables in React and for #5 I don't know how to run a custom script that could swap variables based on the firebase project currently being used on the command line.
Most info I have seen on this doesn't tackle this issue exactly - all the env variables are either only in the cloud functions or distinguish local vs cloud or dev vs prod, but cannot distinguish between two clouds and a local that uses the same config as one of the clouds.
Someone must have had experience with this?
I've finally tracked down an answer to this.
The best way I've found to handle this in React/nextjs is to use a combination of my ideas #4 and #5 from my original question.
As seen here, firebase has a firebase apps:sdkconfig command on the cli that:
Prints the Google services configuration of a Firebase App.
So knowing that, you can add a script to npm that creates a firebase config file each time the site gets built. Since it knows which firebase project you are currently using on the command line, it knows the version of the config to output when you're deploying.
Then, in your package.json, you can set it to run.
"scripts": {
...
"build": "npm run getconfig && next build",
"getconfig": "firebase apps:sdkconfig web --json > ./firebase-config.json",
...
},
Then, in your firebase.js or wherever you're configuring firebase in your app:
// Get the Firebase config from the auto generated file.
const firebaseConfig = require('./firebase-config.json').result.sdkConfig;
// Instantiate a Firebase app.
const firebaseApp = firebase.initializeApp(firebaseConfig);
This works both locally and in the cloud with no manual changes needed other than what you'd already be doing to switch the environment you're using (i.e. firebase use)
You might need to tweak which npm script it runs on or other small things to suit your needs, but this general setup is working great for me with production, staging and development environments.

How to use environment variables in React app hosted in Azure

I'm pretty new to React, and exploring Azure in general as well.
I've gotten an ERP background, but that background did include using tools like VSTS and CI/CD.
I've heavily relied upon using the 'libraries' in VSTS to specify variables per environment, and then specifying these upon deployment.
But! I've been reading around on the internet, and playing with settings, but to my understanding, I can only 'embed' parameters in the actual code that is generated by NPM. This would basically mean that I'd need to create a seperate build per environment, which I'm not used to. I've always been tought (and tell others) that what you ship to production, should be exactly the same as what has been on pre-prod, or staging, or ... . Is there really no other way to use environment variables? I was thinking of using the Application Settings in Azure App Service, but I can't get them to even pop up in the console.
The libraries in VSTS, haven't found how to use these in my deployment either, as there's just one step.
And reading the docs at https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-custom-environment-variables doesn't make me feel comfortable putting .env files in source control either. I even tried the approach of putting
{process.env.NODE_ENV}
in my code, but in Azure it just shows up as 'Development', while I even do npm run build (which should be production)...
So, I'm a bit lost here! How can I use environment variables specified in Azure App Service, in my React app?
Thanks!
The Good Options
I had this problem as well you can customize which env variables are used by using different build scripts for your envs.
Found this CRA documentation
https://create-react-app.dev/docs/deployment/#customizing-environment-variables-for-arbitrary-build-environments
You can also set your variables in your YAML. https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#set-variables-in-pipeline
But what if I need a single build?
I haven't solved this yet if you are using a single build and release stages for different envs (dev, staging, prod). Since everything is built React has whatever env variables you provided at build time. Alternatives I've considered:
Separating react build from .NET build, so that you could do this as for each deploy
Define all env variables and append eg REACT_APP_SOME_KEY_ then based on subdomain pick specific env eg https://dev.yoursite.com https://yoursite.com , but this option seems non-canonical.
Might be a limitation of React needing to build for every environment. Accept that you need separate builds.
Add the venerable directly to build pipeline Variables. This will add to the Azure environment variable and the app can use it
When you do the deployment using VSTS to Azure, you can give your environment variables in the build pipeline which will automatically include it in the ReactJS project.
now the end of 2019 and I am still facing the issue with env variables in nodeJs and azure devops.
I didn't find a solution, but I use a workaround. I use pseudo "env var".
I created "env.json" file with the same structure as ".env" file in the project's root. Put this file to ".gitignore" file. Imported this file explicitly to files where I need to use env var. Use it as regular object, instead of process.env.***
Example:
we have ".env", that we need to replace:
REACT_APP_SOMW_KEY=KEY
The next steps for project itself are:
Create "env.json":
{"REACT_APP_SOMW_KEY":"KEY"}
Add it to ".gitignore".
In case of using typescript add the next settings to tsconfig.json:
"resolveJsonModule": true,
In files where process.env.REACT_APP_SOMW_KEY are located change process.env.REACT_APP_SOMW_KEY to config.REACT_APP_SOMW_KEY and add const config = require("../pathTo/env.json") as a import module in the begginning.
In case of typescript yo can also create interface just to have autocomplete:
export interface IEnvConfig{
REACT_APP_SOMW_KEY?: string;
}
const config: IEnvConfig = require("../pathTo/env.json");
The result will be something like this:
const reactSomeKey = /*process.env.REACT_APP_SOMW_KEY*/ config.REACT_APP_SOMW_KEY;
Next steps for Azure DevOps:
Add your keys to azure "key vault" or "variables".
In the CI pipeline before the step of building the project you can set the PowerShell task, which will create the "env.json" file. The same as we should create ".env" file locally since we made git clone with the hidden ".env" file.
I put yml task here (in the end you can see 2 debug commands just to be sure that file is created and exist in a project):
- powershell: |
New-Item -Path $(System.DefaultWorkingDirectory) -Name "env.json" -Force -Value #'
{
"REACT_APP_SOMW_KEY": "$(REACT_APP_SOMW_KEY)",
}
'#
Get-Content -Path $(System.DefaultWorkingDirectory)\env.json
Get-ChildItem -Path $(System.DefaultWorkingDirectory)
displayName: 'Create "env.json" file'
Outcome: you have almost the same flow with json object keys as you are usually using with ".env". Also you can have both ".env" and "env.json" in the project.
I used a YAML build and wrote the variable to the .env file. The package I was using to do the transforms in reactjs was dotenv version 8.2.0
So here is my YAML build file, with tasks added to accomplish this
variables:
- group: myvariablegroup
trigger:
batch: true
branches:
include:
- develop
- release/*
pool:
vmImage: 'ubuntu-latest'
stages:
- stage: dev
condition: eq(variables['build.sourceBranch'], 'refs/heads/develop')
jobs:
- job: DevelopmentDelpoyment
steps:
- task: CmdLine#2
inputs:
script: 'echo APP_WEB_API = $(myvariable-dev) > Web/.env'
displayName: 'Setting environment variables'
- script: |
cd Web
npm install
npm run build
displayName: 'npm install and build'
- stage: prod
condition: eq(variables['build.sourceBranch'], 'refs/heads/master')
jobs:
- job: ProductionDelpoyment
steps:
- task: CmdLine#2
inputs:
script: 'echo APP_WEB_API = $(myvariable-prod) > Web/.env'
displayName: 'Setting environment variables'
- script: |
cd Web
npm install
npm run build
displayName: 'npm install and build'
This route only applicable if you are using Azure DevOps.
Azure DevOps has Section in Pipeline called Library.
Create a new Variable Group and add your env variables.
Associate last create Variable group to your build process.
Also remember to name your env variable starting with REACT_APP_
All proposed solutions are way too complex because others already have solved this problem during the package and build process.
To deploy this to azure 2 things have to be done. First remove the .ignore rule that excludes the .env* files. NOTE: ASSUMED you do not put secrets here!
Most of the config in the .env file is visible online anyway, during the auth-flow. So, why panic about this file in git? Espially in a private Git I don't see any problem for those .env files.
So, I have .env.dev and a .env.prod...
this contains e.g.
REACT_APP_AUTH_URL=https://auth.myid4.info
REACT_APP_ISSUER=https://auth.myid4.info
REACT_APP_IDENTITY_CLIENT_ID=myclientid
REACT_APP_REDIRECT_URL=https://myapp.info/signin-oidc
REACT_APP_AUDIENCE=
REACT_APP_SCOPE=openid profile email roles mysuperapi
REACT_APP_SILENT_REDIRECT_URL=https://myapp.info/silent-renew
REACT_APP_LOGOFF_REDIRECT_URL=https://myapp.info/logout
API_URL=/
the following must be done.
npm i --save-dev env-cmd
now, modify in package.json like this. You may have some others, but essentially, add just the correct .env for your environment
env-cmd -f .env.prod
so in my case in package.json
"start": "env-cmd -f .env.dev rimraf ./build && react-scripts start",
"build": "env-cmd -f .env.prod react-scripts build"
Now, I deployed my react JS to azure. I use, FYI, the .NET Core Spa feature.
Had the same problem, my environment variables didn't load on azure build and deploy, and after hours of googling and hitting my head against the wall i just ocurred to me that maybe the blanks before and after the equals sign ("=") were not supposed to be there.
So i changed:
REACT_APP_API_URL = https://some_url
For:
REACT_APP_API_URL=https://some_url
And it worked alright !!
Many of the proposed solutions here did not work (and should not work) but I solved it the following way. However, first let me explain why other solutions may not (should not) work (please correct me if I am wrong)
Adding pipeline variables (even though they are environment variables) should not work since a react app is run on the client side and there is no server side code that can inject environment variables to the react app.
Installing environment variable task on the classic pipeline should not work for the same reason.
Adding to Application Settings in azure app service should not work for the same reason.
Having .env or .env.development or .env.production file in a git repo should not be a good practice as it may compromise api keys and other sensitive information.
So here is my solution -
Step1: Add all those .env files to azure devops library as secure files. You can download these secure files in the build machine using a DownloadSecureFile#1 pipeline task (yml). This way we are making sure the correct .env file is provided in the build machine before the task yarn build --mode development in the pipeline.
Step2:
Add the following task in your azure yml pipeline in appropriate place. I have created a github repo https://github.com/mail4hafij/react-yarn-azure-pipeline if you want to see a complete example.
# Download secure file from azure library
- task: DownloadSecureFile#1
inputs:
secureFile: '.env.development'
# Copy the .env file
- task: CopyFiles#2
inputs:
sourceFolder: '$(Agent.TempDirectory)'
contents: '**/*.env.development'
targetFolder: '$(YOUR_DEFINED_PROJECT_ROOT_FOLDER_VARIABLE)'
cleanTargetFolder: false
Keep note, secure files can't be edited but you can always re-upload.
It's not exactly what you are looking for, but maybe this is an alternative solution for your problem (it substitutes the process-env.x into real values during the build step):
https://github.com/babel/minify/tree/master/packages/babel-plugin-transform-inline-environment-variables
As others have said, in your Azure pipeline, add the variable to the pipeline. However some corrections on what others have posted, possibly leveraging newer functionality since their responses were written:
if your variable in your .env file is named REACT_APP_MY_VARIABLE, then the variable you need to add to your Azure pipeline should also be named REACT_APP_MY_VARIABLE (not process.env.REACT_APP_MY_VARIABLE)
when setting up the Azure pipeline variable, you can leave the value empty and check the box for "Let users override this value when running this pipeline". This seems to be the trick to letting react still process the .env file content to retrieve your desired values.
As an update, it's a bit different then my original approach, but I've gone through the route of using DotEnv and thus using .env files, which I will generate on the fly in VSTS, using the library variables, and thus NOT storing them in source control.
To use DotEnv, I updated the webpack.config;
const Dotenv = require('dotenv-webpack');
module.exports = {
...
plugins: [
new Dotenv()
],
Then basically, I created a .env file containing my parameters
MD_API_URL=http://localhost:7623/api/
And to be able to consume them in my TSX files I just use process.env;
static getCustomer(id) {
return fetch(process.env.MD_API_URL + 'customers/' + id, { mode: 'cors' })
.then(response => {
return response.json();
}).catch(error => {
return error;
});
}

Create-React-App + Heroku: Development, Staging and Production environments

I'm developing an app (front-end app that consumes an API) based on the create-react-app package. I'm using Heroku to deploy and currently have two deployments based on the same codebase, staging and production. These deployments should use different development/staging/production APIs that have different databases.
Is it possible to tell create-react-app to use different env variables based on how I run react-scripts start?
env.development
REACT_API: https://localhost/react_api
env.staging
REACT_API: https://myappstagingapi.heroku.com
env.production
REACT_API: https://myappproductionapi.heroku.com
How would I do this? And is this a good workflow?
Thank you very much!
I had the similar situation having more environments than production and development while deployment was done automatically from Github.
First of all, make sure you are using the deployment buildpack i.e.
https://github.com/mars/create-react-app-buildpack.git
You can add this URL in Settings in your project on Heroku, replacing NodeJS default buildpack for instance.
Full documentation is here:
https://elements.heroku.com/buildpacks/nhutphuongit/create-react-app-buildpack
If you follow the link above, you can see the chapter Environment variables. So, in order that your React App can process custom variables:
Add a one that suits you with REACT_APP_ prefix to your Heroku project environment variables (through Settings in Heroku Dashboard) Note that only the envs with this prefix will be visible in your process.env later so you should amend your code accordingly
Redeploy the application.
This should make the things work. I am sure it is also possible to keep .env file but I prefer to have more control via Heroku Dashboard.

.config vs. .env files in node.js w/ heroku

I'm in the process of doing my first deployment of a node.js app on Heroku. While running the app locally I stored API keys and other configuration variables in .config files excluded from version control.
Heroku seems to have built-in support for a ".env" configuration file in the project root and I've refactored my server code to support this. My question is where is the best place to store configuration variables that need to be accessible in the client? I'm running angularjs on the front-end and need to be able to access various API keys.
Is there some way I can reference the same .env file or should I be approaching this differently?

Resources