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 have engineered a build for an Angular SPA using NPM to call the browserify script to bundle it, i.e. you can run from the terminal npm run build:js which calls the following script in package.json:
"build:js": "browserify -r ./params-dev.js -e src/app/index.js -o build/index.js"
What I'm trying to do now is to create two different config objects for prod and QA. Each one will require a different file: params-dev.js or params-prod.js (like in the command above).
I am wondering how to access these variables in the resulting bundle? They are environment specific and some of it points to analytics codes, etc. Furthermore, I'm trying to move them out of the global scope, where they currently live.
Here is a sample of the params files I'd like to include with the bundles. There will be one for prod and one for QA:
var merge = require('merge'),
params = require('./params')
exports.config = merge(params, {
env: 'prod',
analyticsCode: 'blah08yweblah2e823lnblah',
otherProps: '...etc...'
})
So how do I access these variables now in my AngularJS module? I feel like I'm missing something obvious here.
Anyone have any ideas? Please let me know if you need more info.
In case it helps, my index.js looks like
(function () {
// common app require statements
require('blah')
require('blah-2')
angular.module('app', [require('angular-route')])
// etc etc
})()
I figured it out. :) If I add the target to the end of the required file path in the command like so:
"build:js": "browserify -r ./params-dev.js:params -e src/app/index.js -o build/index.js"
I can access the object by adding var params = require('params') to my angular file.
Details:
I have a directory structure like this.
myapp
root-one
-web
-app
-tests
root-two
-grunt
node_modules
.bin
intern-runner
selenium-standalone
intern
selenium-standalone
grunt-shell
Gruntfile.js
From my grunt file I am using shell npm to launch the selenium standalone server like so..
shell: {
intern : {
options: { stdout: true},
command: [
"cd node_modules/.bin",
"start selenium-standalone start",
"intern-runner config=tests/intern basePath=../../../../root-one/web"
].join('&&')
}
}
}
grunt.registerTask('intern', ['shell:intern']);
After running my grunt command grunt intern, selenium starts but I get the following error from intern-runner.
Error: Failed to load module tests/intern
from C:/myapp/root-two/grunt/node_modules/.bin/tests/intern.js
Now because I set the path (or so I thought) using basePath=../../../../root-one/web. I would have expected it to try to execute from C:/myapp/root-one/web/tests/intern.js instead of remaining in the .bin directory.
Question:
So really the question is. What is the proper way to set the basePath for intern-runner on the command line? Because this doesn't seem to work. And according to the docs...
You can also specify any valid configuration option as an argument on
the command-line.
Which leads me to believe I probably just have the syntax wrong.
Sounds like this doesn't quite work the way I was expecting it to. As discussed here: https://github.com/theintern/intern/issues/449
So for now the work around was to just install intern globally vs trying to run it locally out of my project. So instead I did..
npm install intern -g
With my project structure like so...
myapp
root-one
-web
-app
-tests
root-two
-grunt
node_modules
.bin
selenium-standalone
selenium-standalone
grunt-shell
Gruntfile.js
Basically just removed intern because it is installed globally now. Which is located at the following on windows..
C:\Users\user\AppData\Roaming\npm\node_modules\intern
And my Gruntfile has been changed too the following. After starting selenium I change directory back to the appropriate location to run the intern-runner command.
shell: {
intern : {
options: { stdout: true},
command: [
"cd node_modules/.bin",
"start selenium-standalone start",
"cd ../../../../root-one/web",
"intern-runner config=tests/intern
].join('&&')
}
}
}
grunt.registerTask('intern', ['shell:intern']);
Earlier when I was using node.js without grunt I had to simply write the following code to include an external module.
var express = require('express');
After I switched to grunt I am trying to use the following module qr-image.
I am stuck with the use of this module as whenever I use the following command my code breaks.
[ This is as per an official example. ]
var qr = require('../');
To Install this module in my node_modules directory I changed the package.json by adding the following dependency in
"devDependencies": {
.
.
.
"qr-image": "^2.0.0"
},
And then ran npm install command at the root directory level of my app.
Thus, Stuck with the implementation of this node.js qr-image module on grunt. Any help will be appreciated.
I believe the right way to do this is:
var qr = require('qr-image');
You can find an example in the project's readme.
I am trying to use the autoprefixer css post-processor. I am following a tutorial and have installed npm. Using a npm, I then installed grunt and autoprefixer inside my project root using that package.json file: https://github.com/nDmitry/grunt-autoprefixer/blob/master/package.json
Following the tutorial, I then created this Gruntfile.js inside my project root:
module.exports = function (grunt) {
grunt.initConfig({
autoprefixer: {
dist: {
files: {
'build/style.css': 'style.css'
}
}
},
watch: {
styles: {
files: ['style.css'],
tasks: ['autoprefixer']
}
}
});
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-watch');
};
After that the tutorial advises to use Grunt Watch using
./node_modules/.bin/grunt watch
Which results in
-bash: ./node_modules/.bin/grunt: No such file or directory
I also tried to navigate to the grunt folder inside my project, then it says
-bash: node_modules/grunt: is a directory
I also have a node_modules folder directly in my local user folder, but addressing that folder grunt also just tells me that its a folder.
Pleaser help me, why is this not working? I am willing to really learn grunt, but I am not even able to get started using the getting started guide...
Have you installed the grunt-cli? (npm install grunt-cli -g) What happens when you run grunt in your project root? The command you should be running is simply grunt watch, in your project root.
Edit: Your project root must also have a package.json file in which you define your development dependencies; e.g.
{
"name":"yourprojectname",
"version":"0.0.1",
"devDependencies":{
"grunt":"*",
"grunt-contrib-watch":"*",
"grunt-autoprefixer":"*"
}
}
if there is acutally a space in the executable name you need to put it in quotes
"./node_modules/.bin/grunt watch"
otherwise linux will run "./node_modules/.bin/grunt" with watch as a flag.
if that still doesn't work,
could be a few problems, either your ldconfig isn't updated, the files aren't set to executable, or the user you are trying to execute the command with doesn't have permission.
first try running "ldconfig" (just type and run it)
more info here
http://www.cyberciti.biz/tips/linux-shared-library-management.html
chmod -x the files to make them executable.
any luck?