Passing environment variables in npm-scripts - node.js

I have a package.json with following (simplified) content in the scripts key:
...
scripts: {
"start": "NODE_ENV=${NODE_ENV:=production} node start-app.js",
"poststart": "echo $NODE_ENV"
}
...
From the command line I can run:
npm start
This will run my start-app.js script and set the process.env.NODE_ENV environment variable to "production". See here for syntax explanation.
The poststart will automatically run after start as described here.
However poststart will not "inherit" the NODE_ENV shell environment variable, so the echo command will not echo anything.
My producation code is a little more complex, but what I am trying to accomplish is passing down the NODE_ENV variable from the "starting point" to dependent scripts. Any suggestions/best practices on how to do that?
I dont want to hardcode the NODE_ENV in the poststart, because I might want to do:
NODE_ENV=development npm start
and I want everyting "down the chain" inherit the same environment.

You have a few options:
better-npm-run,which can define an env for each command separately
Instead of a poststart script, you can concatenate commands for npm like so: "start": "NODE_ENV=${NODE_ENV:=production} node start-app.js && echo $NODE_ENV"
Use a process manager in production like pm2. pm2 lets you define environment specific json files with settings such as NODE_ENV. At our company, we successfully run all of our apps in different environments with pm2 (all the while having the same start command)

this is how I did it, first you need to install two dev-dependencies
https://www.npmjs.com/package/env-cmd
this load your env var from your file
https://www.npmjs.com/package/cross-env
this use environment variable in script
example scripts:
"env-cmd ./.config/prod.env cross-env-shell \"docker volume create $DOCKER_VOLUME\""
this load $DOCKER_VOLUME env var from prod.env
update:
starting from env-cmd version 10, you need specify -f flag if you want to use a custom env file path
"env-cmd -f ./.config/prod.env cross-env-shell \"docker volume create $DOCKER_VOLUME\""

If you have small use cased, use better-npm-run. For small cases, it works fine. Somehow if you have a lot of commands and it hard manage. Try, batman-cli. Work well and handle lot of environment-dependent issues
npm i -g batman-cli

Related

How can I pass docker environment variables to an npm script?

As the title says...As a noobie I've given this a good attempt but can't seem to figure it out.
I have a dockerfile
FROM node:12
WORKDIR /app
COPY . /app
RUN npm config set registry https://registry.npmjs.org/
RUN npm install
EXPOSE 8080
ENTRYPOINT ["npm", "start",]
CMD [ "--", "-e=$ENVIRONMENT", "-t=$TESTS" ]
and a script in my package.json like so:
"scripts": {
"start": "node main.js"
}
Main.js is expecting two arguments. e & t.
I am struggling to pass these in to the container to then give to the script to run main.js (note there is a reason why im running it through a script ive just made this example simple)
To run my npm script I can do this:
npm start -- -e=abc -t=xyz
So I have tried this but no joy:
docker run -e ENVIRONMENT=abc -e TESTS=xyz myimage
Thanks
When you use the JSON form of CMD (or ENTRYPOINT or RUN), there is no interpolation at all; your script should literally see the string -e=$ENVIRONMENT as the argument. Instead you need to use the shell form, which will wrap this in a shell that expands environment variables. You can't do this with this particular split of ENTRYPOINT and CMD, but at the same time, it's not really necessary; just put the whole thing in CMD.
# No ENTRYPOINT
# No quoting; Docker wraps this in `sh -c ...`
CMD npm start -- -e="$ENVIRONMENT" -t="$TESTS"
You can also handle these directly in your application. The yargs library for example has a .env() function that allows environment variables to be used directly as options. You could also make process.env.TESTS be the default value for the option if it's not provided directly. This approach gets around the trouble of constructing (and possibly extending) a valid command line with the combination of arguments you need.

Access npm task parameters from javascript files

In my package.json I have a script like so:
"start": "runsMyApp --value=tt && node -e 'console.log(process.env)'"
When I run my script
npm run start
I can see my variable logged:
npm_config_value: 'tt'
My question is, can I access the npm_config_value from process.env.npm_config_value in my js files as I can do with process.env.NODE_ENV ?
I can't manage to pick its value, I have also tried with process.npm_config_value without success...
Any hints on this?

How does npm run a script to set system environment which can be used by another npm run script

I set several scripts in package.json of npm, e.g.
{
"scripts": {
"server:install": ". ./scripts/server-install.sh",
"server:start": ". ./scripts/server-start.sh",
"server:stop": ". ./scripts/server-stop.sh",
"test:e2e": "jest --collectCoverage false test/**/*"
}
}
in server-start.sh, I will start dynamoDB service locally and need to set system environment AWS_API_KEY value. The value will be used in test cases when npm run test:e2e.
But, the problem is that the value I set for AWS_API_KEY in server:start can't be used in test:e2e. It seems that the variable set operation in server-start.sh will not change the system variables of current console/sessions.
I googled and tried like:
"server:start": "AWS_API_KEY=dummy . ./scripts/server-start.sh"
or by using cross-env
"server:start": "cross-env-shell AWS_API_KEY=dummy && . ./scripts/server-start.sh"
Both failed. The only left idea I can think of is to write the AWS_API_KEY to ~/.bash_profile. I don't want to do that.
Any help will be much appreciated.

Running Meteor Build under Node with settings argument

Typically when developing I would use meteor run --settings settings.json. This works fine and can view the settings in the browser with Meteor.settings on the console.
I am now build for production, using meteor build, I've looked at the documentation and there is nowhere to add settings during the build process.
So the build runs and I have my .tar.gz file, it's loaded to production and then I untar/compress the folder and run the start script.
It enters the program with npm start and the package.json section looks like this (ignore the stop script);
{
"name": "myapp",
"scripts": {
"start": "node main.js --settings settings.json",
"stop": "killall node"
}
}
When I look at my app it is not collecting these settings. It is as if when bundled it doesn't expect the arguements. I also tried using forever beforehand, but I had no joy with this either.
Any help would appreciated, start to wish I never bothered with Meteor :)
You can refer to Meteor Guide > Production > Deployment and Monitoring > Environment variables and Settings
Settings. These are in a JSON object set via either the --settings Meteor command-line flag or stringified into the METEOR_SETTINGS environment variable.
As for setting environment variables, if you use a 3rd party host, you may have a GUI or CLI to define them.
Otherwise, you should have plenty resources including on SO:
Node.js: Setting Environment Variables
How can I set an environmental variable in node.js?
https://themeteorchef.com/snippets/making-use-of-settings-json/
In short, it should look like:
METEOR_SETTINGS='{"key":"value"}' node main.js
You can also try the bash cat command to extract the content of a file: $(cat settings.json)

How to use nodemon/grunt with .env files?

I am using an .env file to work with foreman, but am trying to configure nodemon to start my server using grunt, because I enjoy how nodemon restarts when files become modified.
I am trying avoid having an .env file for foreman AND having environment variables stored in my ~/.bash_profile for nodemon. Instead, I would like to configure my .env file to work for both cases.
I found some answers here, and the second answer should work for grunt.
My .env file is of JSON format, which should flatten environment variables via concatenation (see here).
When I run the following command $ env $(cat .env) nodemon app.js, I receive the following error: env: {: No such file or directory.
Anyone have an idea of what the problem may be? Cheers.
I'd suggest filing this at http://github.com/remy/nodemon/issues/new - but I'd also say that there's environment config support in nodemon as of 1.0.9 - though I'm not 100% sure it'll solve what you want.
Basically you put a nodemon.json file in your home directory, and have:
{
"env": {
"USER": "remy",
"PORT": "8000",
"ETC": "etc"
}
}
An example of the config can be seen here and a few more details here.
I haven't tried using the nodemon. But I've figured out how to do restart the server using foreman.
Define a key on your Procfile to run your application with node-supervisor
My proc file have a dev key that is like this: dev: node-supervisor -w .,lib/ webserver.js
The -w option is a comma separated list of the folders that you want to watch.

Resources