I previously asked (and got a great answer for) this question: named parameter to npm run script
As mentioned in 1 of the comments to the correct answer, the $npm_config_variable does not work on windows. I'm looking for a cross platform way to run this script as npm run say-hello --greeting='hello'.
Is there any way to check for the OS in npm scripts and use %% instead of $?
Use minimist library. Its realy easy to access command line params with it and it works in every environment.
var argv = require('minimist')(process.argv.slice(2));
var param = argv.param;
// package.json snippet
"scripts": {
"start": "app --param=value"
}
Related
I am minifying multiple files in a folder using uglifyjs-folder in npm package.json like :
"uglifyjs": "uglifyjs-folder js -eyo build/js"
It is working as intended & minify all files in folder.
I want to remove any console.log & alert while minify but not able to find any option with uglifyjs-folderhttps://www.npmjs.com/package/uglifyjs-folder
Please help.
Short Answer
Unfortunately, uglifyjs-folder does not provide an option to silence the logs.
Solution
You could consider writing a nodejs utility script which utilizes shelljs to:
Invoke the uglifyjs-folder command via the shelljs exec() method.
Prevent logging to console by utilizing the exec() methods silent option.
The following steps further explain how this can be achieved:
Install
Firstly, cd to your project directory and install/add shelljs by running:
npm i -D shelljs
node script
Create a nodejs utility script as follows. Lets name the file: run-uglifyjs-silently.js.
var path = require('path');
var shell = require('shelljs');
var uglifyjsPath = path.normalize('./node_modules/.bin/uglifyjs-folder');
shell.exec(uglifyjsPath + ' js -eyo build/js', { silent: true });
Note: We execute uglifyjs-folder directly from the local ./node_modules/.bin/ directory and utilize path.normalize() for cross-platform purposes.
package.json
Configure the uglifyjs script inside package.json as follows:
{
...
"scripts": {
"uglifyjs": "node run-uglifyjs-silently"
...
},
...
}
Running
Run the script as per normal via the command line. For example:
npm run uglifyjs
Or, for less logging to the console, add the npm run --silent or shorthand equivalent -s option/flag. For example:
npm run uglifyjs -s
Notes:
The example gist above assumes that run-uglifyjs-silently.js is saved at the top-level of your project directory, (i.e. Where package.json resides).
Tip: You could always store run-uglifyjs-silently.js in a hidden directory named .scripts at the top level of your project directory. In which case you'll need to redefine your script in package.json as follows:
{
...
"scripts": {
"uglifyjs": "node .scripts/run-uglifyjs-silently"
...
},
...
}
uglify-folder (in 2021, now?) supports passing in terser configs like so:
$ uglify-folder --config-file uglifyjs.config.json ...other options...
and with uglifyjs.config.json:
{
"compress": {
"drop_console": true
}
}
And all options available here from the API reference.
The title of my question is how to run a command line tool from a node.js application because I think an answer here will apply to all command line utilities installable from npm. I have seen questions related to running command line from node.js, but they don't seem to be working for my situation. Specifically I am trying to run a node command line utility similar to npm (in how it is used, but not its function) called tilemantle.
tilemantle's documentation shows installing tilemantle globally and running the program from the command line.
What I would like to do is install tilemantle locally as a part of a npm project using npm install tilemantle --save and then run tilemantle from inside my project.
I've tried `tilemantle = require('tilemantle'), but the index.js file in the tilemantle project is empty, so I think this won't help with anything.
I tried the project node-cmd
const cmd = require('node-cmd');
cmd.run('./node_modules/tilemantle/bin/tilemantle', 'http://localhost:5000/layer/{z}/{x}/{y}/tile.png', '-z 0-11', '--delay=100ms', '--point=37.819895,-122.478674', '--buffer=100mi'
This doesn't throw any errors, but it also just doesn't work.
I also tried child processes
const child_process = require('child_process');
child_process.exec('./node_modules/tilemantle/bin/tilemantle', 'http://localhost:5000/layer/{z}/{x}/{y}/tile.png, -z 0-11 --delay=100ms --point=37.819895,-122.478674 --buffer=100mi'
This also doesn't throw any errors, but it also doesn't work.
Is there a way to get this working, so that I can run tilemantle from inside my program and not need to install it globally?
Update
I can get tilemantle to run from my terminal with
node './node_modules/tilemantle/bin/tilemantle', 'http://localhost:5000/layer/{z}/{x}/{y}/tile.png', '--delay=100ms', '--point=37.819895,-122.478674', '--buffer=100mi', '-z 0-11'
If I run the following as suggested by jkwok
child_process.spawn('tilemantle', ['http://myhost.com/{z}/{x}/{y}.png',
'--point=44.523333,-109.057222', '--buffer=12mi', '-z', '10-14'],
{ stdio: 'inherit' });
I am getting spawn tilemantle ENOENT and if I replace tilemantle with ./node_modules/tilemantle/bin/tilemantle.js I get spawn UNKNOWN
Based on jfriend00's answer it sounds like I need to actually be spawning node, so I tried the following
child_process.spawn('node', ['./node_modules/tilemantle/bin/tilemantle.js', 'http://myhost.com/{z}/{x}/{y}.png', '--point=44.523333,-109.057222', '--buffer=12mi', '-z', '10-14'], { stdio: 'inherit' });
Which gives me the error spawn node ENOENT which seems strange since I can run it from my terminal and I checked my path variable and C:\Program Files\nodejs is on my path.
Just to check I tried running the following with a full path to node.
child_process.spawn('c:/program files/nodejs/node.exe', ['./node_modules/tilemantle/bin/tilemantle.js', 'http://myhost.com/{z}/{x}/{y}.png', '--point=44.523333,-109.057222', '--buffer=12mi', '-z', '10-14'], { stdio: 'inherit' });
which runs without the ENOENT error, but again it is failing silently and is just not warming up my tile server.
I am running Windows 10 x64 with Node 6.11.0
You can install any executable locally and then run it with child_process. To do so, you just have to figure out what the exact path is to the executable and pass that path to the child_process.exec() or child_process.spawn() call.
What it looks like you ultimately want to run is a command line that does:
node <somepath>/tilemantle.js
When you install on windows, it will do most of that for you if you run:
node_modules\.bin\tilemantle.cmd
If you want to run the js file directly (e.g. on other platforms), then you need to run:
node node_modules/tilemantle/bin/tilemantle.js
Note, with child_process, you have to specify the actual executable which in this case is "node" itself and then the path to the js file that you wish to run.
This, of course, all assumes that node is in your path so the system can find it. If it is not in your path, then you will have to use the full path to the node executable also.
It looks like you are trying to capture the output of tilemantle from running a file rather than from the command line. If so, I did the following and got it to work.
Installed tilemantle and child_process locally into a new npm project as you did, and added the following into a file in that project.
// test.js file
var spawn = require('child_process').spawn;
spawn('tilemantle', ['http://myhost.com/{z}/{x}/{y}.png', '--
point=44.523333,-109.057222', '--buffer=12mi', '-z', '10-14'], { stdio: 'inherit' });
Run it using node test.js inside the project.
I tried a bunch of the other options in this post but could only get the above one to print the progress along with other output. Hope this helps!
Many command line utilities come with a "programmatic" API. Unfortunately, tilemantle does not, which is why you are unable to require that module in your code.
You can, however, easily access a locally installed version of the CLI from npm scripts. I don't know anything about tilemantle, so I'll provide an example using the tldr command line tool. In your package.json:
{
"name": "my-lib",
"version": "1.0.0",
"scripts": {
"test": "tldr curl"
},
"dependencies": {
"tldr": "^2.0.1"
}
}
You can now run npm test from the terminal in your project as an alias for tldr curl.
Per this post, you can use the global-npm package to run npm scripts from your code:
const npm = require('global-npm')
npm.load({}, (err) => {
if (err) throw err
npm.commands.run(['test'])
})
And voila, you can now run the locally installed CLI programmatically(ish), even though it has not offered an API for that.
I use foreverjs to start my services. Also I use nodejs v5 with nvm. Running on mac.
Everything working fine yesterday, but today (after npm update) I suddenly have an errors like /node_modules/my-service-one/node_modules/my-service-onewhen I'm try to npm start.
The project structure is:
.
|-package.json
|-services.json
|+-node_modules
|-forever
|-my-service-one
|-my-service-two
Config for foreverjs (services.json):
[
{
"append": true,
"uid": "my-service-one",
"script": "index.js",
"sourceDir": "node_modules/my-service-one"
},
{
"append": true,
"uid": "my-service-two",
"script": "index.js",
"sourceDir": "node_modules/my-service-two"
}
]
And I launch it with npm start(package.json):
...
"scripts": {
"start": "node_modules/forever/bin/forever start services.json",
}
...
But when I try to make npm start, I have an error:
Error: Cannot find module '/Users/my_user/project_name/node_modules/my-service-one/node_modules/my-service-one/index.js'
WTF is this: /node_modules/my-service-one/node_modules/my-service-one? Why?
It should use /node_modules/my-service-one/index.js. So why?
UPD: What I've already try(without result):
rm -rf node_modules;
Restart;
Use node v4, v5, v6;
npm cache clean;
Find other node_modules in wrong places inside project;
Google it;
This is bad question perhaps, but I'm really didn't know why it's happens. Thanks.
Have you tried to launch this modules with forever from command line?
This path issue looks like a bug for me, I think the obvious duct-tape type fix is use absolute path in services.json instead of relative. It will look terrible but it should work.
But I think it's better to install forever globally (with -g key) and then use a simple shell script to start your services with forever (two lines with something forever start /Users/my_user/project_name/node_modules/my-service-one/index.js) - this way works fine for me.
And also it's quite easy to start this script at the boot-up, or even write a script to start and stop your modules as a service.
UPD: This also may helps: sourceDir: './'
I want to only allow certain version of node and npm before the user can run his npm install on my module.
In the NPM documentation, there is an engine attribute, dedicated to this task:
"engines": {
"node": ">=4.0.0",
"npm": ">=3.0.0"
}
These parameters will only allow node and npm versions up to 4 and 3.
However, the documentation says that the engine-strict attribute should be enabled in order to check the versions. On engine-strict, it is said that:
This feature was deprecated with npm 3.0.0
So, is there a way, with npm3, to define minimal Node and NPM versions for a module?
Yarn checks the engine out of the box at the time of installation. But with npm, you may have to write a custom validator at this moment for checking node versions before firing a script.
export function verifyNodeVersion(version) {
const nodeVersion = process.versions.node;
if (!nodeVersion.startsWith(`${version}.`)) {
throw new Error(
`Incorrect version of Node found: ${nodeVersion}, Expected: v${version}.x`
);
}
console.log('Current Node version:', nodeVersion);
return true;
}
And call the function in the entry points.
So, is there a way, with npm3, to define minimal Node and NPM versions for a module?
engines does that. It's just that it does it by A) Outputting an advisory message warning the user if their system isn't up-to-scratch, and B) Failing if the user has set the engine-strict config flag.
All the documentation is saying is that engineStrict is no longer supported to push the user around. :-) If they want to ignore the advisory messages and not use the engine-strict config flag, then caveat user.
Normally when pointing node to a folder, if there is an index.js file there, we don't need to specify it.
I installed an NPM dependency that I am working on, npm install --save-dev suman.
Suman has an index.js file at the root of its NPM project.
In my NPM scripts for a project that depends on suman, I have this:
"scripts": {
"test": "node node_modules/suman/index.js --rnr test"
}
The above works!
But this doesn't work:
"scripts": {
"test": "node node_modules/suman --rnr test"
}
Why is this?
Perhaps the answer is obvious - the require function in node is capable of such behavior, but node itself is not.
Since the library has a bin in its package.json, you don't need to explicitly provide the path to it. Just run node suman --rnr test and npm will take care of using the correct file.
When you install a dependency with a binary in your node project, npm creates a symlink to that file in ./node_modules/.bin and uses those when running npm scripts.
You need to add the correct path:
"scripts": {
"test": "node ./node_modules/suman --rnr test"
}
Notice the ./
Update:
After thinking about this a bit more, It may not be this easy. But take a look at this link: https://docs.npmjs.com/misc/scripts - #elssar seems to be on the right track.
Sorry that I can't include my thoughts simply as a comment rather than as an answer but I don't yet have enough reputation points to comment. However, perhaps the following is relevant:
If, in your problem, the node command finds the appropriate index.js the same way as is shown in the node documentation for modules, then the documented look-up routine will find a different index.js before finding the one that (I think) you want. Specifically, before trying node_modules/suman/index.js (which is the one you want), node will look to see if the "main" field in node_modules/suman/package.json exists. In suman, it does, and it references lib/index.js (i.e. node_modules/suman/lib/index.js) which is different than the one you want. Is that relevant?
UPDATE: Just to clarify my answer with more generic language...
Your original question is a valid one because, in the absence of any other complications, if dir/index.js exists, then both of the following
node dir/index.js ...
node dir ...
should refer to the same (default) file, i.e. dir/index.js. Thus it is reasonable to be confused when those two commands give different results. The explanation is that there IS a complication: the dir/package.json file effectively redirects node dir ... to use a non-default file. This is because the "main" property refers to dir/some/other/file.js. The rules of precedence specify that, if only a directory name is used, this other file will be used before the default. Thus, you are forced to continue to use the longer and more explicit "working" command from your question.