I noticed this strange behavior which is not a big deal, but bugging the heck out of me.
In my package.json file, under the "scripts" section, I have a "start" entry. It looks like this:
"scripts": {
"start": "APPLICATION_ENV=development nodemon app.js"
}
typing npm start on a Mac terminal works fine, and nodemon runs the app with the correct APPLICATION_ENV variable as expected. When I try the same on a Windows environment, I get the following error:
"'APPLICATION_ENV' is not recognized as an internal or external command, operable program or batch file."
I have tried the git-bash shell and the normal Win CMD prompt, same deal.
I find this odd, because typing the command directly into the terminal (not going through the package.json script via npm start) works fine.
Has anyone else seen this and found a solution? Thanks!!
For cross-platform usage of environment variables in your scripts install and utilize cross-env.
"scripts": {
"start": "cross-env APPLICATION_ENV=development nodemon app.js"
}
The issue is explained well at the link provided to cross-env. It reads:
Most Windows command prompts will choke when you set environment variables with NODE_ENV=production like that. (The exception is Bash on Windows, which uses native Bash.) Similarly, there's a difference in how windows and POSIX commands utilize environment variables. With POSIX, you use: $ENV_VAR and on windows you use %ENV_VAR%.
I ended up using the dotenv package based on the 2nd answer here:
Node.js: Setting Environment Variables
I like this because it allows me to setup environmental variables without having to inject extra text into my npm script lines. Instead, they are using a .env file (which should be placed on each environment and ommitted from version control).
You should use "set" command to set environment variables in Windows.
"scripts": {
"start": "set APPLICATION_ENV=development && nodemon app.js"
}
Something like this.
Related
I want to create a hash on build and set is as environment variable. It should be accessible by node.
Firstly I wrote a bash script, exported the environment variable in the script and sourced it in the package.json.
Problem is node doesn't know the source command.
Now I rewrote the script in Typescript (due to the whole project using TS not JS).
In the script I set the variable as follows:
process.env.VARIABLE = hashFunction(path);
The function is called through a script in package.json
"hash": "ts-node path/to/script.ts"
The function works as it should, but the environment variable is not set. Can someone help me to resolve this? Is it possible to return the string outside of the script and set it from there?
If possible i'd like to not use an external package.
Thank you :)
Update:
I used a bash script, but with a typescript script it'd work the same way. For bash the console.log is replaced with echo.
script.ts
console.log("2301293232") // The hash created by the script
package.json
"scripts": {
"build": "yarn run hash react-scripts build", // omit &&
"hash": "ENV_VAR=$(ts-node script.ts)"
}
So I did the following:
The script returns the checksum to the console/standard output. But I'll capture it before and set the printed value as environment variable in the package.json file. This will work as long as its the same process which starts the build.
That is why neither
"scripts": {
"build": "yarn run hash && react-scripts build"
}
nor
"scripts": {
"build": "react-scripts build",
"prebuild": "ENV_VAR=$(ts-node script.ts)"
}
will work. In both examples a new process will be started and the environment variable will be lost.
Can't (easily) change environment variables for parent process
You can change/set the environment for the currently running process. That means that when ts-node runs your program, you are changing the environment variables for your script and for ts-node.
After your script is finished running, ts-node stops, and the environment changes are lost. They don't get passed back to the shell.
Changing another process's environment
Changing the environment variables for the parent process (the shell) is a much more complicated process and depends on your OS and upon having the correct permissions. For linux, one such technique is listed here. In Windows, you can find some hints by looking at this question.
Other options
Your other option might be to just return a string that your shell understands, and run that.
Our team has built a small CLI used for maintenance. The package.json specifies a path for with the bin property, and everything works great; "bin": { "eddy": "./dist/src/cli/entry.js"}
Autocompletion is achived by using yargs#17.0.1. However we recently converted the project to use es6 modules, because of a migration to Sveltekit, i.e. the package.json now contains type: module. Because of this, the CLI now only works if we run with:
what works
node --experimental-specifier-resolution=node ./dist/src/cli/entry.js help
However, if we run this without the flag, we get an error "module not found":
Error [ERR_MODULE_NOT_FOUND]: Cannot find module...
So the question is
Can we somehow "always" add the experimental-specifier-resolution=node to the CLI - so we can continue to use the shorthand eddy, and utilize auto completion?
There are two probable solutions here.
Solution 1
Your entry.js file should start with a shebang like #!/usr/bin/env node. You cannot specify the flag directly here, however, if you could provide the absolute path to node directly in the shebang, you can specify the flag.
Assuming you have node installed in /usr/bin/node, you can write the shebang in entry.js like:
#!/usr/bin/node --experimental-specifier-resolution=node
(Use which node to find the absolute path)
However, this is not a very portable solution. You cannot always assume everyone has node installed in the same path. Also some may use nvm to manage versions and can have multiple version in different path. This is the reason why we use /usr/bin/env to find the required node installation in the first place. This leads to the second solution.
Solution 2
You can create a shell script that would intern call the cli entry point with the required flags. This shell script can be specified in the package.json bin section.
The shell script (entry.sh) should look like:
#!/usr/bin/env bash
/usr/bin/env node --experimental-specifier-resolution=node ./entry.js "$#"
Then, in your package.json, replace bin with:
"bin": { "eddy": "./dist/src/cli/entry.sh"}
So when you run eddy, it will run the entry.js using node with the required flag. The "$#" in the command will be replaced by any arguments that you pass to eddy.
So eddy help will translate to /usr/bin/env node --experimental-specifier-resolution=node ./entry.js help
Just add a script to your package.json:Assuming index.js is your entry point and package.json is in the same directory
{
"scripts": {
"start": "node --experimental-specifier-resolution=node index.js"
}
}
Then you can just run on your console:
npm start
I follow this post to configure NextJs to use absolute paths, like this:
//package.json:
...
"scripts": {
"dev": "NODE_PATH=. next",
"build": "NODE_PATH=. next build",
"start": "next start"
},
NodeJs, npm and nextJs app are up to date both on windows and Linux.
It works on Linux, but when i try to build on a Windows, it fails with the error
'NODE_PATH' is not recognized as an internal or external command, operable program or batch file.
Update
I find out that npm is just running SO scripts, so in windows, the equivalent for:
NODE_PATH=. next
wold be:
set NODE_PATH=. & next
But doesn't work because the command set does not affect the context of the second command
set X=1 & echo %X% returns
%X% //for first run. doesn't consider it a variable because doesn't know her
1 //for second run
Can't figure out how to overcame this last problem
works from outside:
>set NODE_PATH=.
>npm run dev
Should be some better solution somewhere
Am following the tutorial by Mosh in Node.js and I am not able to make this line of code work.
DEBUG=app:db nodemon index.js
I got an error which is:
'DEBUG' is not recognized as an internal or external command,
operable program or batch file.`
While in his end it is working fine.
Is this only works on MAC? I've also tried
set DEBUG=app:db nodemon index.js
But still get the same error.
Well, I've seen and tried these answers but still didn't work for me.
Could someone explain why this doesn't work?
Try this "set DEBUG=app:* & nodemon index.js" on Windows. Then refresh your browser you will see the connection to the database.
Using windows, you must separate commands with && separator:
"scriptCommand": "set DEBUG=app:db&& nodemon index.js"
Please note the there is NO space between db and &&. This is intentional, as the variable space spreads all the way to the && wall - meaning it will add an unintentional space after db to your variable.
Also, you perhaps would like to try the very useful and self-explanatory cross-env library which allows you to use 1 syntax to declare an environment variable in any env (Win, Mac, Linux) the project is initialized in
I am very new to node.js and npm. I was trying to setup an open source project locally on my windows and I got this error
'NODE_ENV' is not recognized as an internal or external command,
operable program or batch file.
So I edited build:bundle in package.json, SET NODE_ENV=xyz from NODE_ENV=xyz. It installed the project properly then.
My question is, Is there a way to tell npm to use SET NODE_ENV=xyz on windows and NODE_ENV=xyz on linux/mac, so that I can create a fix without breaking the entire project.
Install and use the package named cross-env
$ npm install --save-dev cross-env
Run scripts that set and use environment variables across platforms
You can then use one syntax, so the build:bundle script will be something like this:
...
"scripts": {
"build:bundle": "cross-env NODE_ENV=xyz ...",
...
}