ENV not recognized in bash? from Npm script call - node.js

So my .env file looks as such:
ENV=DEV
My check_env.sh looks as such:
#!/usr/bin/env bash
if [ "$ENV" = "DEV" ]
then
yarn start:dev
elif [ "$ENV" = "PROD" ]
then
yarn start:prod
else
echo "ENV : has not been set yet..."
fi
And my npm script call is as such: "start": "./check_env.sh"
I get the message: ENV : has not been set yet...
How exactly is the ENV not set? Am I failing epically at something here?

Related

Check file exists before launch it in webpack npm scripts

I have a package.json like this:
...
"scripts": {
"dev": "webpack --config webpack.dev.config.js --mode development --progress --colors",
"postdev": "if (Test-Path \"./postdev.sh\" ) { echo \"file exists\"; ./postdev.sh }"
},
...
How can I check if file "postdev.sh" exists and then launch it in NPM-scripts section?
I run that command in the terminal and it goes correctly, but if I try to launch that npm-script it says "Unexpected appearance: "./postdev.sh"."
on macos or linux try this one for postdev:
"postdev": "test -f ./postdev.sh && echo 'file exisits' && ./postdev.sh",
Finnally found a solution (maybe it works only on Windows, but it is enough for me):
"postdev": "if exist postdev.sh ( postdev.sh )",
You can use path-exists-cli package, a cross-platform tool, to check if a file/directory exists and use && or || after to run the next command if exists or not, respectively:
{
"scripts": {
// other scripts...
"postdev": "path-exists ./postdev.sh && echo 'Exists' || echo 'Does not exists'"
}
}

Propagate arguments to two commands combined with &&

I have two commands in package.json combined with '&&':
"scripts": {
"someAction": "node dist/scripts/actionOne && node -r dist/scripts/actionTwo"
},
Is it possible to call this script from cli, passing arguments to both 'actionOne' and 'actionTwo' ?
When calling
npm run someAction -- firstArg, secondArg args are passed only to 'actionOne' script.
*Number of args expected by actionOne and actionTwo are identical.
After looking at the docs, it looks like npm-run-all would work with argument placeholders.
We can use placeholders to give the arguments preceded by -- to scripts.
$ npm-run-all build "start-server -- --port {1}" -- 8080
This is useful to pass through arguments from npm run command.
{
"scripts": {
"start": "npm-run-all build \"start-server -- --port {1}\" --"
}
}
$ npm run start 8080
> example#0.0.0 start /path/to/package.json
> npm-run-all build "start-server -- --port {1}" -- "8080"
So you could do something like this:
{
"scripts": {
"start": "npm-run-all dist/scripts/actionOne -- --arg {1} && dist/scripts/actionTwo -- --arg2 {2}"
}
}
Then:
npm run start arg1 arg2
If there is a real answer, I wanna know. But also, you can make a script like this
some-action.sh
set -e
dist/scripts/ActionOne $#
dist/scripts/ActionTwo $#
and then put this in your package.json
"scripts": {
"someAction": "bash some-action.sh"
},

How to fix node.js using sails error: Failed to lift app

I’m trying to deploy a node.js app using the framework Sails in production mode.
I’m using the command npm start which runs NODE_ENV=production node app.js. In package.json I have the following content:
{
"name": "myapp",
"private": true,
"version": "0.0.0",
"description": "a Sails application",
"keywords": [],
"dependencies": {
"sails": "^1.2.3",
"grunt": "1.0.4",
"sails-hook-apianalytics": "^2.0.3",
"sails-hook-grunt": "^3.0.2",
"sails-hook-organics": "^0.16.0",
"sails-hook-orm": "^2.1.1",
"sails-hook-sockets": "^2.0.0",
"#sailshq/connect-redis": "^3.2.1",
"#sailshq/socket.io-redis": "^5.2.0",
"#sailshq/lodash": "^3.10.3"
},
"devDependencies": {
"eslint": "5.16.0",
"htmlhint": "0.11.0",
"lesshint": "6.3.6",
"#sailshq/eslint": "^4.19.3",
"sails-hook-grunt": "^4.0.0"
},
"scripts": {
"start": "NODE_ENV=production node app.js",
"test": "npm run lint && npm run custom-tests && echo 'Done.'",
"lint": "./node_modules/eslint/bin/eslint.js . --max-warnings=0 --report-unused-disable-directives && echo '✔ Your .js files look so good.' && ./node_modules/htmlhint/bin/htmlhint -c ./.htmlhintrc views/*.ejs && ./node_modules/htmlhint/bin/htmlhint -c ./.htmlhintrc views/**/*.ejs && ./node_modules/htmlhint/bin/htmlhint -c ./.htmlhintrc views/**/**/*.ejs && ./node_modules/htmlhint/bin/htmlhint -c ./.htmlhintrc views/**/**/**/*.ejs && ./node_modules/htmlhint/bin/htmlhint -c ./.htmlhintrc views/**/**/**/**/*.ejs && ./node_modules/htmlhint/bin/htmlhint -c ./.htmlhintrc views/**/**/**/**/**/*.ejs && ./node_modules/htmlhint/bin/htmlhint -c ./.htmlhintrc views/**/**/**/**/**/**/*.ejs && echo '✔ So do your .ejs files.' && ./node_modules/lesshint/bin/lesshint assets/styles/ --max-warnings=0 && echo '✔ Your .less files look good, too.'",
"custom-tests": "echo \"(No other custom tests yet.)\" && echo",
"deploy": "echo 'This script assumes a dead-simple, opinionated setup on Heroku.' && echo 'But, of course, you can deploy your app anywhere you like.' && echo '(Node.js/Sails.js apps are supported on all modern hosting platforms.)' && echo && echo 'Warning: Specifically, this script assumes you are on the master branch, and that your app can be deployed simply by force-pushing on top of the *deploy* branch. It will also temporarily use a local *predeploy* branch for preparing assets, that it will delete after it finishes. Please make sure there is nothing you care about on either of these two branches!!!' && echo '' && echo '' && echo 'Preparing to deploy...' && echo '--' && git status && echo '' && echo '--' && echo 'I hope you are on the master branch and have everything committed/pulled/pushed and are completely up to date and stuff.' && echo '********************************************' && echo '** IF NOT THEN PLEASE PRESS <CTRL+C> NOW! **' && echo '********************************************' && echo 'Press CTRL+C to cancel.' && echo '(you have five seconds)' && sleep 1 && echo '...4' && sleep 1 && echo '...3' && sleep 1 && echo '...2' && sleep 1 && echo '...1' && sleep 1 && echo '' && echo 'Alright, here we go. No turning back now!' && echo 'Trying to switch to master branch...' && git checkout master && echo && echo 'OK. Now wiping node_modules/ and running npm install...' && rm -rf node_modules && rm -rf package-lock.json && npm install && (git add package-lock.json && git commit -am 'AUTOMATED COMMIT: Did fresh npm install before deploying, and it caused something relevant (probably the package-lock.json file) to change! This commit tracks that change.' || true) && echo 'Deploying as version:' && npm version patch && echo '' && git push origin master && git push --tags && (git branch -D predeploy > /dev/null 2>&1 || true) && git checkout -b predeploy && (echo 'Now building+minifying assets for production...' && echo '(Hang tight, this could take a while.)' && echo && node node_modules/grunt/bin/grunt buildProd || (echo && echo '------------------------------------------' && echo 'IMPORTANT! IMPORTANT! IMPORTANT!' && echo 'ERROR: Could not compile assets for production!' && echo && echo 'Attempting to recover automatically by stashing, ' && echo 'switching back to the master branch, and then ' && echo 'deleting the predeploy branch... ' && echo && echo 'After this, please fix the issues logged above' && echo 'and push that up. Then, try deploying again.' && echo '------------------------------------------' && echo && echo 'Staging, deleting the predeploy branch, and switching back to master...' && git stash && git checkout master && git branch -D predeploy && false)) && mv www .www && git add .www && node -e 'sailsrc = JSON.parse(require(\"fs\").readFileSync(\"./.sailsrc\", \"utf8\")); if (sailsrc.paths&&sailsrc.paths.public !== undefined || sailsrc.hooks&&sailsrc.hooks.grunt !== undefined) { throw new Error(\"Cannot complete deployment script: .sailsrc file has conflicting contents! Please throw away this midway-complete deployment, switch back to your original branch (master), remove the conflicting stuff from .sailsrc, then commit and push that up.\"); } sailsrc.paths = sailsrc.paths || {}; sailsrc.paths.public = \"./.www\"; sailsrc.hooks = sailsrc.hooks || {}; sailsrc.hooks.grunt = false; require(\"fs\").writeFileSync(\"./.sailsrc\", JSON.stringify(sailsrc))' && git commit -am 'AUTOMATED COMMIT: Automatically bundling compiled assets as part of deploy, updating the EJS layout and .sailsrc file accordingly.' && git push origin predeploy && git checkout master && git push origin +predeploy:deploy && git push --tags && git branch -D predeploy && git push origin :predeploy && echo '' && echo '--' && echo 'OK, done. It should be live momentarily on your staging environment.' && echo '(if you get impatient, check the Heroku dashboard for status)' && echo && echo 'Staging environment:' && echo ' 🌐–• https://staging.example.com' && echo ' (hold ⌘ and click to open links in the terminal)' && echo && echo 'Please review that to make sure it looks good.' && echo 'When you are ready to go to production, visit your pipeline on Heroku and press the PROMOTE TO PRODUCTION button.'"
},
"main": "app.js",
"repository": {
"type": "git",
"url": "git://github.com/xxxxxx.git"
},
"author": "me",
"license": "",
"engines": {
"node": "^10.16"
}
}
If I run sails lift all gone right.
And when run npm start I get following error:
error: Failed to lift app: Error: Should not specify a trailing slash, but instead got: https://myapp.herokuapp.com/
at checkOriginUrl (/home/me/Documents/prog/myapp/node_modules/sails-hook-sockets/lib/util/check-origin-url.js:57:40)
at /home/me/Documents/prog/myapp/node_modules/sails-hook-sockets/lib/configure.js:86:9
at arrayEach (/home/me/Documents/prog/myapp/node_modules/#sailshq/lodash/lib/index.js:1470:13)
at Function.<anonymous> (/home/me/Documents/prog/myapp/node_modules/#sailshq/lodash/lib/index.js:3532:13)
at Hook.configure (/home/me/Documents/prog/myapp/node_modules/sails-hook-sockets/lib/configure.js:85:9)
at Hook.wrapper [as configure] (/home/me/Documents/prog/myapp/node_modules/#sailshq/lodash/lib/index.js:3282:19)
at /home/me/Documents/prog/myapp/node_modules/sails/lib/app/private/loadHooks.js:331:20
at /home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:3083:16
at eachOfArrayLike (/home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:1003:9)
at eachOf (/home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:1051:5)
at Object.eachLimit (/home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:3145:5)
at configure (/home/me/Documents/prog/myapp/node_modules/sails/lib/app/private/loadHooks.js:328:17)
at /home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:3853:24
at replenish (/home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:946:17)
at iterateeCallback (/home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:931:17)
at /home/me/Documents/prog/myapp/node_modules/sails/node_modules/async/dist/async.js:906:16
I’m trying to use heroku to deploy the app. For this reason I added this in production.js inside sockets object:
onlyAllowOrigins:[
'https://myapp.herokuapp.com/',
],
I think this problem could be caused by any missed configuration in production.js but I couldn’t identify what.

How to use environment variables in package.json

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.
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"
}
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
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 your package.json, that way it will be run on every npm install
Add your private git repos to package.json using the URLs you want (note: they all must have a package.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
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://git#bitbucket.org/foo/bar.git"
Which doesn't contain anything sensitive.
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.
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.
https://docs.npmjs.com/misc/config#environment-variables
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"
}
...
You can install package https://www.npmjs.com/package/env-cmd
and all your envs from .env file will be visible
ie:
./.env:
ENV1=THANKS
ENV2=FOR ALL
ENV3=THE FISH
Package.json:
"scripts": {
"test": "env-cmd pact-broker can-i-deploy --broker-token=${ENV1}"
}
or another example from your question:
"my-private-module":"env-cmd git+https://${BB_USER}:${BB_PASS}#bitbucket.org/foo/bar.git"
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?"
}
If you're running node inside a Docker container
Use Docker Compose to inject the env variable
app:
environment:
- NODE_ENV=staging
Run your package.json script from your Dockerfile
CMD [ "npm", "run", "start" ]
Use echo or printenv
"scripts": {
"start": "node -r dotenv/config app.js dotenv_config_path=/run/secrets/$(echo $NODE_ENV)"
"start": "node -r dotenv/config app.js dotenv_config_path=/run/secrets/$(printenv NODE_ENV)"
}
Don't use this for sensitive env variables. It's a really good way to point to a Docker secrets file (like this example shows).

shell function can't be called in node

I have these:
An shell executable file:
function print() {
echo 1
}
The package.json` file
{
"name": "tests",
"scripts": {
"test": "./shell.sh"
}
}
When I ran npm test on a linux machine, I got this error
> tests# test /home/xxxx/test
> ./shell.sh
./shell.sh: 1: ./shell.sh: Syntax error: "(" unexpected
npm ERR! Test failed. See above for more details.
Why so? Anybody has some insight? I am totally puzzled.
This doesn't really have anything to do with Node or npm, but with the shell script missing the shebang.
Try instead e.g.
#!/bin/sh
# Note the new line above
function print() {
echo 1
}

Resources