How to use environment variables in package.json
node.jsHerokuNpmpackage.jsonnode.js Problem Overview
Because we don't want sensitive data in the project code, including the package.json file, using environment variables would be a logical choice in my opinion.
Example package.json:
"dependencies": {
"accounting": "~0.4.0",
"async": "~1.4.2",
"my-private-module":"git+https://${BB_USER}:${BB_PASS}@bitbucket.org/foo/bar.git"
Is this possible?
The question is not if this is wise or not good, just if it's possible.
node.js Solutions
Solution 1 - node.js
In case you use .env
file, let's use grep
or eval
to get a value environment variable from the .env file.
Updated start2
as @Paul suggested:
"scripts": {
"start": "NODE_ENV=$(grep NODE_ENV .env | cut -d '=' -f2) some_script",
"start2": "eval $(grep '^NODE_ENV' .env) && some_script"
}
Solution 2 - node.js
I have similar but different requirement. For me, I want to use environment variables in the scripts.
Instead of using the environment variables directly in package.json, I do:
"some-script": "./scripts/some-script.sh",
And in some-script.sh:
#!/bin/sh
npm run some-other-script -- --prop=$SOME_ENV_VAR
Solution 3 - node.js
No, it's not possible. You should access the repo using git+ssh
, and store a private key in ~/.ssh
.
Your line then looks like:
"my-private-module":"git+ssh://[email protected]/foo/bar.git"
Which doesn't contain anything sensitive.
Solution 4 - node.js
Here's how I managed to work around package.json
to achieve the same purpose. It uses a script that reads from a custom section of package.json
for URL modules, interpolates environment variables in them, and installs them with npm install --no-save
(the --no-save
could be omitted, depending on the usecase).
As a bonus: it tries to read the env variable from .env.json
, which can be gitignore'd, and very useful for development.
- Create a script that will read from a custom section of
package.json
env-dependencies.js
const execSync = require('child_process').execSync
const pkg = require('./package.json')
if (!pkg.envDependencies) {
return process.exit(0)
}
let env = Object.assign({}, process.env)
if (typeof pkg.envDependencies.localJSON === 'string') {
try {
Object.assign(env, require(pkg.envDependencies.localJSON))
} catch (err) {
console.log(`Could not read or parse pkg.envDependencies.localJSON. Processing with env only.`)
}
}
if (typeof pkg.envDependencies.urls === 'undefined') {
console.log(`pkg.envDependencies.urls not found or empty. Passing.`)
process.exit(0)
}
if (
!Array.isArray(pkg.envDependencies.urls) ||
!(pkg.envDependencies.urls.every(url => typeof url === 'string'))
) {
throw new Error(`pkg.envDependencies.urls should have a signature of String[]`)
}
const parsed = pkg.envDependencies.urls
.map(url => url.replace(/\${([0-9a-zA-Z_]*)}/g, (_, varName) => {
if (typeof env[varName] === 'string') {
return env[varName]
} else {
throw new Error(`Could not read env variable ${varName} in url ${url}`)
}
}))
.join(' ')
try {
execSync('npm install --no-save ' + parsed, { stdio: [0, 1, 2] })
process.exit(0)
} catch (err) {
throw new Error('Could not install pkg.envDependencies. Are you sure the remote URLs all have a package.json?')
}
-
Add a
"postinstall": "node env-dependencies.js"
to yourpackage.json
, that way it will be run on everynpm install
-
Add your private git repos to
package.json
using the URLs you want (note: they all must have apackage.json
at root!):
"envDependencies": {
"localJSON": "./.env.json",
"urls": [
"git+https://${GITHUB_PERSONAL_ACCESS_TOKEN}@github.com/user/repo#semver:^2.0.0"
]
},
(the semver specifier #semver:^2.0.0
can be omitted, but refers to a git tag, which can be very useful, as it makes your git server a fully-fledge package manager)
npm install
Solution 5 - node.js
No it isn't possible as npm does not treat any string values as any kind of templates.
It may be better to just use git+ssh
(if your provider supports it) with an ssh agent.
Solution 6 - node.js
You can use environment values to inject in your package.json like this:
> Any environment variables that start with npm_config_ will be interpreted as a configuration parameter. For example, putting npm_config_foo=bar in your environment will set the foo configuration parameter to bar. Any environment configurations that are not given a value will be given the value of true. Config values are case-insensitive, so NPM_CONFIG_FOO=bar will work the same.
Solution 7 - node.js
I had the same need and my solution was based on @Long Nguyen's response. This way, I can only rely on what's defined on the .env file.
.env
...
SKIP_PREFLIGHT_CHECK=true
...
package.json
...
"scripts": {
"test": "yarn cross-env $(grep SKIP_PREFLIGHT_CHECK ../../.env) react-app-rewired test --watchAll=false"
}
...
Solution 8 - node.js
For complicated environment variables, you can use https://stedolan.github.io/jq/ to access JSON file (env file at your case) JSON file could be something like
{
"env" :
{
"username" : "1345345",
"Groups" : [],
"arraytest" : [
{
"yes" : "1",
"no" : "0"
}
]
}
}
so the script could be something like this to access yes value
"scripts": {
"yes": "jq [].arraytest[0].yes?"
}