How to set some flags on my node build - node.js

When I build, test and deploy my node application from Codeship to Heroku I want to be able to set a release flag to true using a command line during the build. And in my code I want to do something like this....
if(config.release) load(liveConnection);
else load(debugConnection);
How can I achieve this? Is there some sort of package I install to run a build script which will transform my config file?

Instead of using a config file, you should use environment variables. For example:
heroku config:set NODE_ENV=production
Then, in node:
if (process.env.NODE_ENV === 'production') load(etc);
An even better way is to just provide connection information uniformly, through config files, like this:
heroku config:set CONNECTION_STRING=foo
Then in node:
load(process.env.CONNECTION_STRING);
That way, the environment is providing the config. Locally, you can start the app with a development string like CONNECTION_STRING=some_debug_string node server.js, or you can use a .env file to provide a whole set of them. More info here:
http://12factor.net/config

Related

How to add environment variables to AWS amplify?

I have a React/Node app which i am trying to host on AWS amplify. first try, my app deployed but i saw some pages are not loading due to lack of the environment variables.
i have added them to the AWS console before deploying and it did not work. then i did some search and i saw that i need to modify "amplify.yml" file to:
build:
commands:
- npm run build:$BUILD_ENV
but not only it did not work, also the app is not working anymore.
any ideas?
As this question specifically references React, here are the steps you need to use environment variables in your React based application in AWS Amplify.
In your client-side JS:
const BUILD_ENV = process.env.REACT_APP_BUILD_ENV || "any-default-local-build_env";
The key thing to note here is my pre-fix of REACT_APP_ which is covered the Create-React-App docs: here
Now, in your Amplify console, under App Settings > Environment variables:
Finally, you also need to add this reference under App Settings > Build Settings:
Note: "BUILD_ENV" can be any string you wish. Within the environment variables you can provide the necessary DEV / PROD overrides.
DO NOT store SECRET KEYS using this method, AWS provide a secrets manager for this. This method is for publishable keys, like connecting to Firebase or Stripe and the key is fine to be public.
The Amplify documentation on Environmental Variables has a section on "Accessing Environmental Variables".
Per that documentation, in your Amplify.yml (either in the console or by downloading it to the root of your project), you can use a command to push Amplify Environmental Variables into your .env. If you created an Environmental Variable in Amplify called "REACT_APP_TEST_VARIABLE" you would do...
build:
commands:
- echo "REACT_APP_TEST_VARIABLE=$REACT_APP_TEST_VARIABLE" >> .env
- npm run build
Once in your .env you can access them through process.env...
console.log('REACT_APP_TEST_VARIABLE', process.env.REACT_APP_TEST_VARIABLE)
If you are using Create React App, you already have dotenv, or see Adding an .env file to React Project for more info.
Obligatory reminder to add your .env to your .gitignore, and don't store anything in .env that is sensitive.
To get #leandro's answer working I had to wrap the AWS environment variable names in curly braces:
build:
commands:
- npm run build
- VARIABLE_NAME_1=${VARIABLE_NAME_1}
Probably better as a comment but I don't have enough points to post one.
#A Zarqam Hey man, I ran into this issue ans spent a decent amount of time on it. What worked for me was:
On my React code, use process.env.VARIABLE_NAME
On my webpack.config.js use the following plug-in:
new webpack.EnvironmentPlugin(['VARIABLE_NAME_1', 'VARIABLE_NAME_2'])
On the Amplify environment variables put the VARIABLE_NAME_1,etc and then the values, just like in the docs says.
Last on the build settings:
build:
commands:
- npm run build
- VARIABLE_NAME_1=$VARIABLE_NAME_1
(the one with $ is a reference to the one you put in amplify. Also I think you must have no spaces between the = symbol)
Then trigger a build, and cross your fingers.
Just to add to other comments regarding Secret keys, since SO doesn't let me comment until 50 rep... If you're not using those Env Variables in your front-end app such as process.env.<var_name>, and only use them during build time, you're fine. Those files will not be bundled into your front-end app.
I know this question is related to frontend apps but its title appeared in search engines for me even though I was looking for build variables only, so it might be useful for other people too.
An add on to #leandro's for anyone checking for this in the future I just want to simplify what you need to do since I was completely lost on this:
In your code reference all API keys as process.env.EXAMPLE_API_KEY_1
Run this in your root folder terminal npm install react-app-rewired --save-dev
Add config-overrides.js to the project root directory.(NOT ./src)
// config-overrides.js
module.exports = function override(config, env) {
// New config, e.g. config.plugins.push...
return config
}
Set your variables in AWS Amplify with your key and variable, pretty self-explanatory.
In your build settings make it look something like this (I personally don't add npm build in here but you can if you need to.)
frontend:
phases:
build:
commands:
- EXAMPLE_API_KEY_1=${EXAMPLE_API_KEY_1}
- EXAMPLE_API_KEY_2=${EXAMPLE_API_KEY_2}
Start or restart your build.
I used #leandro's answer and mixed in an answer from this question to get it to work for me.
This worked for me to deploy React to Amplify
amplify.yml
version: 1
frontend:
phases:
preBuild:
commands:
- npm install
build:
commands:
- npm run build
artifacts:
baseDirectory: build
files:
- '**/*'
cache:
paths:
- node_modules/**/*
in App.js
const client = new ApolloClient({
uri:
process.env.NODE_ENV !== 'production'
? 'http://localhost:1337/graphql'
: process.env.REACT_APP_ENDPOINT,
cache: new InMemoryCache(),
});

Node js express project how to add environment variables

I am a java script full stack developer.
In the vue js I create two files in the root.
env.development
env.production
In my main.js file, I can access environment variables like this
process.env.VUE_APP_MY_VARIABLE_X
How production and development differs in the vue js is,
if I use npm run serve project loaded the development environment variables. If I use npm run build it takes production environment variables. That's all in vue.
But in my expressjs project,
"start": "nodemon server.js --exec babel-node -e js",
This command will always responsible for the run project. I couldn't find two commands like in vue. I go though the tutorials every body says use the package called dotenv.
I couldn't figure out that how could this package identify the environments this is production and this is development.
End of the day I want to set my db password to 123456 in my local machine and root#123456 in the server. How could I achieve this?
Vue.js handles modes automatically, depending on the command (e.g. serve sets NODE_ENV=development, while build sets NODE_ENV=production).
Depending on the mode, it also automatically loads files with variables from disk.
Environment variables in Node.JS
However, Node.JS does not do that by default, and you have to set up your application to handle environment variables.
In Node.JS you can pass variables via the shell command, for example:
MY_VARIABLE=x node myapp.js (by prepending the command with variables), and that will give you process.env.MY_VARIABLE inside your myapp.js application.
Following this behavior, there's a consensus on using NODE_ENV variable for setting up the environment mode.
For production use, you'd start your application using NODE_ENV=production node myapp.js, while for development NODE_ENV=development node myapp.js.
Of course, if your machine already has these environment variables set up (for instance in .bash_profile) you do not need to prepend your command with them.
As a practice, in development machines, you'd have these variables already set up on your machine, while production machines (e.g. docker containers, etc) start clean and you pass the environment variables when starting your application.
For example, Heroku (and other deployment services) allow you to set up environment variables which are set at machine start.
There's also the method of storing variables in files (such as the .env, or other files), but those you'd have to read from disk when your application starts.
And this is where dotenv (and config package) come in play.
What dotenv does, is it reads .env file stored in your application execution path (root of the app), and sets any variables defined there into process.env for Node.JS to use.
This is extremely useful for development machines, but on production it's recommended to not have files that store sensitive information in variables, but rather use system environment variables.
There is also the option, for production machines, to construct or load into the machine an .env file at machine setup time, into the app directory.
Note:
never commit .env or config files that store passwords and sensitive information, to your repository
never store development and production variables in the same file
The dotenv approach
The best way to go about it, would be to use dotenv, and have different .env files, one on your development machine, and a different one on your production machine. That way, when your application starts, it reads the variables that are stored in the adjacent .env. This is the most secure and reliable way, in absence of means to pass environment variables to your production machine from a machine management application/interface.
The easiest way to set up your app with dotenv would be to set your start command to something like:
"start": "nodemon --exec \"node -r dotenv/config\" server.js"
and then in the .env file stored on your local/development machine you'd have something similar to:
DATABASE_PASSWORD=1235
DATABASE_USERNAME=joe-dev
...
and in the .env file on your production machine (server):
DATABASE_PASSWORD=root#1235
DATABASE_USERNAME=root
...
according to my understanding
you don't have created and setup a config file and required it in your app.js or any other file. let see for example create config file
const config = {
"development":{
"host":"localhost",
"dbport":"27017",
"port":"",
"username":"",
"password":"",
"userdb":"",
"passworddb":"123456",
"authSource":"",
"database":"devDB"
},
"staging":{
"host":"",
"dbport":"",
"port":"",
"username":"",
"password":"",
"passworddb":"#123456",
"database":"stageDB",
},
"production":{
"host":"",
"dbport":"",
"port":"",
"userdb":"",
"passworddb":"#123456",
"username":"",
"password":"",
"database":"prodDB",
}
};
module.exports = config;
then you have you setup a variable in your .env file like NodeENV = 'prod'
then import it into your files like
var config = require('./config')["process.env.NodeENV"];
and one more last thing dotenv is only used to loads environment variables from a .env file into process.env.

create react app cannot read environment variable after build

I have a react app , created with create-react-app then I build the app with command: npm run build
It's using serve to run the app after build, if we start the app with development code by running ENV=production npm run start it can read the process.env.ENV variable beacause I'm adding this plugins to webpack dev config
new webpack.DefinePlugin({
'process.env':{
'ENV': JSON.stringify(process.env.ENV),
}
}),
I also add the script above to webpack prod config, but if I try this command after build ENV=prod serve -s build, it cannot read the environment variable
How to fix this?
If you set all the environment variables inside the app.config.js, you can replace them after the build in the main.????????.chunk.js file.
A sample app.config.js could look like:
export default {
SOME_URL: "https://${ENV_VAR_1}"
SOME_CONFIGURATION: "${ENV_VAR_2}",
}
Leave the app.config.js file as is, without replacing the environment variables with their actual values. Then, create the optimized production build:
npm ci # if not already installed
npm run build
If the default webpack configurations are used, the contents of app.config.js will be bundled in build/static/js/main.????????.chunk.js. The values of the environment variables can be be envsubst, with a bash script like this:
main_chunk=$(ls build/static/js/main.*.js)
envsubst <$main_chunk >./main_chunk_temp
cp ./main_chunk_temp $main_chunk
rm ./main_chunk_temp
Note: In the above example, envsubst reads the actual variables set in the environment at runtime and literally replaces ${ENV_VAR_1} and ${ENV_VAR_2} with them. So, you can only run this once as the chunk is being over-written.
The reason why you can not read the ENV var is because:
(1) In development mode webpack watches your files and bundles you app on the fly. It also will read (because of the DefinePlugin) your process.env.ENV and will add it as a global variable. So it is basically piping variables from process.env to your JS app.
(2) After you've build your app (with webpack) everything is already bundled up into one or more files. When you run serve you just start a HTTP server that serves the static build files. So there is no way to pipe the ENV to you app.
Basically what the DefinePlugin does is add a var to the bundle. E.g.
new webpack.DefinePlugin({
'token': '12356234ga5q3aesd'
})
will add a line similar to this:
var token = '12356234ga5q3aesd';
since the JS files is static there is no way to change this variable after you've build/bundled it with webpack. Basically, when you do npm run build you're creating the compiled binary/.dll/.jar/... file and can no longer influence its contents via the plugin.
You can add a .env file to the root of your project and define your environment variables there. That will be your default (production) environment variables definition. But then you can have a local file called .env.local to override values from the default.
When defining your environment variables, make sure they start with REACT_APP_ so your environment variable definitions would look like this:
REACT_APP_SERVER_URL=https://my-awesome-app.herokuapp.com
Also, add this to .gitignore so you don't commit your local overrides:
.env*.local
Reference:
Adding Development Environment Variables In .env (create-react-app)
From create-react-app documentation:
Your project can consume variables declared in your environment as if
they were declared locally in your JS files. By default you will have
NODE_ENV defined for you, and any other environment variables starting
with REACT_APP_.
You can read them from process.env inside your code:
render() {
return (
<div>
<small>You are running this application in <b>{process.env.NODE_ENV}</b> mode.</small>
<form>
<input type="hidden" defaultValue={process.env.REACT_APP_NOT_SECRET_CODE} />
</form>
</div>
);
}

Is there a programmatic way to know a node.js app is running in Heroku?

Is there some variable or function I can call to know if a node.js application is running inside Heroku? Something like:
if (process.heroku)
console.log("I'm in Heroku!");
You can do this without setting custom environment variables. You can do it like this:
if (process.env._ && process.env._.indexOf("heroku") !== -1)
console.log("I'm in Heroku!");
This is possible because on a Heroku dyno the _ environment variable is set to /app/.heroku/node/bin/node.
You use for that usual environment variables.
Just set some variable on your heroku instance and check this:
process.env.HEROKU
On the heroku cli you would do:
heroku config:set HEROKU=true
You can also set it on the web interface, see heroku docs for more:
https://devcenter.heroku.com/articles/config-vars
On this specific case I've used if test -d /app; then npm run build; fi which can be used also inside npm-scripts.

Node JS, detect production environment

When I'm in dev mode I don't want my server to send email and some other stuff so I have this in server.js file:
process.env.NODE_ENV = 'development';
When I move it to production i change the value to 'production'.
Problem is of course that it is easy to forget on deployments. Is it possible somehow to detect when server is in production?
If it's not, is it possible to write a batch script that replaces a string in a file?
You shouldn't manually change values of process.env object, because this object is reflecting your execution environment.
In your code you should do the following:
const environment = process.env.NODE_ENV || 'development';
And then you launch your app in production like this:
$ NODE_ENV=production node app.js
If NODE_ENV environment variable is not set, then it will be set to development by default.
You could also use dotenv module in development to specify all environment variables in a file.
Furthermore, I've implemented a reusable module, which allows to automatically detect environment by analyzing both CLI arguments and NODE_ENV variable. This could be useful on your development machine, because you can easily change environment by passing a CLI argument to you Node.js program like this: $ node app.js --prod. It's also nice to use with Gulp: $ gulp build --prod.
Please see more details and use cases on the detect-environment's page.
The suggested way to tackle these kind of problems is by using the process global object provided by NodeJS. For example:
var env = process.env.NODE_ENV || "development";
By the above line. We can easily switch between development / production environment. If we haven't configured any environment variable it works with development environment.
process.env is an object that contains the user environment.
For example if we are running our application in a bash shell and have configured NODE_ENV to production. Then i can access that in node application as process.env.NODE_ENV.
There are multiple ways to define this NODE_ENV variable for nodejs applications:
## Setting environment variable for bash shell
export NODE_ENV=production
## Defined while starting the application
NODE_ENV=production node app.js
So i don't think you would require any batch file for this. When handling multiple configuration variables, follow this.
This is normally handled through configuration files (e.g. config frameworks like node-convict) and through environmental variables. In the start command in production, you might do something like:
NODE_ENV=production npm start
then the process.env.NODE_ENV would be properly set by any module in your app that cares.

Resources