Why is process.env returning an empty object, while process.env.prop returns the prop value? - node.js

So I have the simplest example on a node machine running with a react-redux app with webpack (Though I don't think any of this matters for the issue expect it being on nodejs).
Specific calls get a value pack:
console.log(process.env.NODE_ENV); // output: 'development'
General calls get nothing back:
console.log(process.env); // output: {}
What am I missing here?
Addition info the might be relevant:
I am using dotenv for the test environment.
I am using dotenv-webpack for the development environment.
I am not using neither of those for the production environment deployed to Heroku
The problem persists on all environments.

The issue with process.env variable being empty in browser is because browser doesn't have real access to the process of the node.js. It's run inside the browser though.
Usage of process.env.ANYTHING is usually achieved by plugins like https://webpack.js.org/plugins/define-plugin/ which just simply replace any occurrence of process.env.ANYTINHG with env variable during BUILD time. It really does just simple str.replace(/process.env.ANYTING/value/) this needs to be done during build time as once you output dist bundle.js you don't have access to the ENV variables.
Replacing during build time
Therefore you need to be sure that when you are producing production build e.g with yarn build you are using webpack.DefinePlugin and replacing those process.env calls with current ENV values. They can't be injected in runtime.
Injecting in runtime
When you need to access env variables in runtime it's basically impossible in JavaScript in browser. There are some sort of hacks for example for NGINX which can serialize current env variables to the window.ENV variable and in your app you will not use process.env but window.ENV. So you need to either have ENV variables available while you are building the application or build mechanism which will dynamically output current ENV as json to window and access with react. If you are using docker it can be done with ENTRYPOINT otherwise you need some bash script which will always output current ENV variables as JSON to the index.html of your app

Related

Using System environment variables in node / react with docker

I have a react app (CRA) it will be running inside a docker container for which I will set an environment variable "API_KEY" = "some_value". For the example of windows this is System Properties -> Environment Variables -> System Variables -> Variable = "API_KEY" and Value = "some_value".
I would like to access to get this variable into the application at run time. This is for the API_KEY for Azure App Insights.
https://learn.microsoft.com/en-us/azure/application-insights/app-insights-javascript#add-the-sdk-script-to-your-app-or-web-pages
The above link shows the <your instrumentation key>. I will be deploying the same application to multiple environments. Each instance of the application will need to use its specific App Insights. So the goal here is to specify that API_KEY in the environment variables which will be different for each of the docker containers.
Please note I am aware of nodeJs and process.env.API_KEY but this does not read from the systems environment variables. Is there a way to get the system variable to link up to the process.env for the node instance?
-PS this request is to an API service that will need to fire straight away. So making an API request to get it is out of the question. It will be exposed to the end client as it is logging JavaScript events for each client.
The answer is NO. You can not read system environment variables. You can however set process environment variables in a *.env file. In my case I will generate this env file via a shell script which will be triggered by the Dockerfile. This will then scrap the process for it's environment variables that start with "REACT_APP_#".
Hope this helps others.
Generating shell script
https://medium.com/#vietgoeswest/passing-env-variables-from-the-server-to-your-create-react-app-c87578a45358
Setting up env with CRA
https://medium.com/#tacomanator/environments-with-create-react-app-7b645312c09d
Dockerizing a Node.js web app
https://nodejs.org/en/docs/guides/nodejs-docker-webapp/
Passing environment variables from Docker to Node https://medium.com/#felipedutratine/pass-environment-variables-from-docker-to-my-nodejs-or-golang-app-a1f2ddec31f5
Also helpful
https://github.com/facebook/create-react-app/issues/982

How to get environment variables defined in serverless.yml in tests

I am using the serverless framework for running lambda functions on AWS.
In my serverless.yml there are environment variables that are fetched from SSM.
When I write integration tests for the code, I need the code to have the environment variables and I can't find a good way to do this.
I don't want to duplicate all the variables definitions just for the tests, they are already defined in the serverless.yml. Also, some are secrets and I can't commit them to source conrol, so I would have to also repeat them in the ci environment.
Tried using the serverless-jest-plugin but it is not working and not well maintained.
Ideas I had for solutions:
Make the tests exec sls invoke - this will work but would mean that the code cannot be debugged, I won't know the test coverage, and it will be slow.
Parse the serverless.yml myself and export the env variables - possible but rewriting the logic of pulling the SSM variables just for tests seems wrong.
Any ideas?
The solution we ended up using is a serverless plugin called serverless-export-env.
After adding this plugin you can run serverless export-env to export all the resolved environment variables to an .env file. This resolves ssm parameters correctly and made integration testing much simpler for us.
BTW, to get the environment variables set from the .env file use the the dotenv npm package.
Credit to grishezz for finding the solution
You can run node with --require option to inject .env file to a serverless command.
Create .env at the project root with package.json, and list variables in .env.
Install serverless and dotenv in the project by yarn add -D serverless dotenv.
Run a command like node -r dotenv/config ./node_modules/.bin/sls invoke.
Then, you can get environment variables in the handler process.env.XXX.
Are you looking to do mocked unit tests, or something more like integration tests?
In the first case, you don't need real values for the environment variables. Mock your database, or whatever requires environment variables set. This is actually the preferable way because the tests will run super quickly with proper mocks.
If you are actually looking to go with end-to-end/integration kind of approach, then you would do something like sls invoke, but from jest using javascript. So, like regular network calls to your deployed api.
Also, I would recommend not to store keys in serverless.yml. Try the secret: ${env:MY_SECRET} syntax instead (https://serverless.com/framework/docs/providers/aws/guide/variables#referencing-environment-variables), and use environment variables instead. If you have a ci/cd build server, you can store your secrets there.
After searching I did my custom solution
import * as data from './secrets.[stage].json'
if( process.env.NODE_ENV === 'test'){
process.env = Object.assign( data, process.env );
}
//'data' is the object that has the Serverless environment variables
The SLS environment variables in my case at the file secrets.[stage].json
Serverless.yml has
custom:
secrets: ${file(secrets.[stage].json)}

How can I access runtime environment variables from a webpack-compiled script that runs in node?

We package and ship a web server that runs in node, using webpack (an admittedly unusual scenario).
In this web server, I would like to access runtime environment variables, not the environment variables from the compile-time run of webpack. However, process.env just contains { NODE_ENV: 'development' }.
Is there some way of accessing the actual runtime process's environment?
The replacement of process.env is actually done by changing code that accesses that variable. If you access it programmatically in a way that avoids this, you will be able to use the underlying variable which is still present:
// avoid cunning webpack replacement of process.env code
let process_env = {}
for (var a of ['env']) {
process_env = process[a]
}
console.log(process.env.HOME) // this gives undefined
console.log(process_env.HOME) // this works

How to get Heroku to ignore a failed import?

I've got a project deployed on heroku using React and node, for which I'm importing a json file which contains various API keys (for firebase, AWS, etc.). In development, I simply do import keys from './keys.json'. However I was aware that wouldn't work in Heroku, so I set up the appropriate environment vars and used process.env to get them. Now though... the whole compilation/build of my project fails because Heroku can't find keys.json (since I don't deploy it, for apparent reasons). Is there any way to get it to ignore this one particular failure during build so it can go ahead and use the env vars?
Wrap the import in a conditional:
var keys = {}
if (!process.env['AWS_KEY']) {
keys = require('./keys.json')['keys'];
}
This has the side effect of giving precedence to environment variables over a local file. If you want the file to have precedence instead, look at fs.existsSync as your conditional (fs.exists could be used with some work).

How can I set up a node app (ember app kit) on heroku that reads ENV variables and makes the values available to the application?

Okay, I'm new to node, and really only just using the node server to serve static js, but I can't find any info on this anywhere.
I'm running an application ember app kit, which gets built to a node server.js for deploy, and heroku runs it with node server.js.
It uses grunt for building, testing, etc.
I'd like to know how I can specify configuration variables (i.e. authentication tokens) that can be overridden by heroku config variables.
The closest I've been able to get is a custom task that reads environment variables and writes out a json file that gets built into the site (and assigned to a global var). This works locally, but doesn't take into account heroku configs.
I even wrote a deploy script that gets heroku's configs, exports them as environment variables locally, and does the build--Which works, but the configs only get updated on app deploy. So if I do a heroku config:add CONFIG_TEST=test_value, my app doesn't see that value for CONFIG_TEST until the next time I deploy the app.
I'd like for my app to start embedding that config value in the browser JS immediately.
Any way to do this with node the way my app is set up?
I am not sure I understand what's wrong with simply taking config variables, at run time, from the environment. Use process.env.KEY in your code, and embed that result into whatever template you may have, and serve that as the result.
When you change Heroku config variables your process gets restarted, so it picks up the new values.
Is the problem the fact that you serve static files? If so -- can you simply change it so that you use a template engine to do some processing on them before serving?
OK, here's a solution for ember-app-kit using grunt-sed.
In EMBER_APP_KIT_PROJECT/tasks/options/sed.js
Add something like
module.exports = {
version: {
path: "./dist/",
pattern: '{{env.API_BASE_PATH}}',
replacement: function(){
return process.env.API_BASE_PATH;
},
recursive: true
}
};
then in your code just put
"{{env.API_BASE_PATH}}"
Now, when you run
$ grunt sed
it will replace "{{env.API_BASE_PATH}}" with whatever's in the environment variable.

Resources