Node Global Install Error - javascript

I'm trying to make a Node module that, when installed with -g, will run by a single command from a terminal.
All tutorials show its pretty straightforward, so I don't know what I'm missing. Here's what I've done:
Package.json:
...
"bin": {
"myapp": "./lib/myapp.js"
},
...
npm publish
npm install -g myapp
I then try to run it globally:
$ myapp
I then get a glob of errors, which honestly looks like it's trying to run a bash script while reading my app, which is a JS file. Here's the output:
$ myapp
.../io.js/v2.0.2/bin/myapp: line 1: $'\r': command not found
.../io.js/v2.0.2/bin/myapp: line 2: /**
.../io.js/v2.0.2/bin/myapp: line 3: package.json: command not found
.../io.js/v2.0.2/bin/myapp: line 4: */
.../io.js/v2.0.2/bin/myapp: line 5: $'\r': command not found
.../io.js/v2.0.2/bin/myapp: line 6: `var _ = require('lodash')
$
See - it looks like its not trying to interpret JS. Here's the header of my JS file it's trying to run:
/**
* Module dependencies
*/
var _ = require('lodash')
Not sure what I'm doing wrong, but I can't find anyone else having this problem online.

See - it looks like its not trying to interpret JS.
Right, the "binary" should be a shell script. You can still write it in JS, you just have to tell the shell which interpreter to use. E.g. you can add
#!/usr/bin/env node
to the top of the file, which tells the shell to use node to interpret the rest of the script.

npm adds a symlink to the file you identify so that it appears on your path. So in this instance, it is literally trying to execute the file as it would any script. You need to add a #! line to the file so your shell knows how to execute it.
For example:
#!/usr/bin/env node
/**
* Module dependencies
*/
var _ = require('lodash')
The #! line is especially important on Windows, as npm looks for that and creates the appropriate .bat file wrapper that knows how to run your script within a node environment.

Related

Pass command line arguments to NodeJS script from NPM script

I have a main script (publish-all.js) from which I want to invoke the npm publish script of an Angular project, which also has a sub-script (publish.js that does general stuff (creating folders, copying files, moving folders...) after ng build.
I need to pass some environment variables to that second script.
I am using shelljs to run unix-like commands.
I tried using:
npm run publish -- VERSION=${productVersion} DESTDIR=${productDestinationPath}
From publish-all.js where productVersion and productDestinationPath are constants declared above that line, and which invokes the following script from the package.json:
"publish": "ng build --prod && node ./scripts/publish.js"
But the actual command line I get is
ng build --prod && node ./scripts/publish.js "VERSION=value" "DESTDIR=value"
Finally, in my publish.js script I tried getting those variables the following way:
let version = process.env.VERSION;
let destinationPath = process.env.DESTDIR;
But I get undefined values.
What am I doing wrong? Is the a better way of doing all this?
Should I maybe use process.argv instead??
I am using this strategy because it is what I were told to do, but I would like to know if there is a less confusing way.รง
EDIT 2021-07-13
I tried using export (with shelljs, since I am in Windows and using powershell) but I am getting an exception.
I have the following code in publish-all.js now:
shelljs.exec(`export VERSION=${productVersion}`);
shelljs.exec(`export DESTDIR=${productDestinationPath}`);
shelljs.exec('npm run publish');
And in the publish.js script from the ANGULAR project:
version = process.env.VERSION;
destinationPath = process.env.DESTDIR;
Though it does not get to publish.js. It gets stuck in the shelljs.exec('npm run publish'), with the following exception:
I had to hide the project folder because of privacy policies, but it is a subfolder inside the folder where I am executing publish-all.js.
Environmental variables go BEFORE the command. So, instead of passing them after you can add them BEFORE:
VERSION=${productVersion} DESTDIR=${productDestinationPath} npm run publish
Or,
You can export the variables first then run the script:
export VERSION=${productVersion}
export DESTDIR=${productDestinationPath}
npm run publish

I have a trouble during npm loading module

I run this commands:
Matias#PC MINGW64 ~/Desktop/test2
$ npm init
[ ... ]
$ npm install
$ npm install neataptic --save
$ npm install chai --save
$ electron .
App threw an error during load
ReferenceError: neataptic is not defined
at Object.<anonymous> (C:\Users\Matias\Desktop\test2\neat.js:6:36)
[...]
The line 6 of the file neat.js is:
/* Shorten var names */
var { architect, Network, methods, config } = neataptic;
I tried also require('neataptic').
But I have that error.
Where am I wrong? Thank you
First off, I assume from your tags, that you're trying to run this in node.js.
From looking at the source, if the neaptaptic module is properly installed, you should be able to do this:
const { architect, Network, methods, config } = require('neataptic');
If, for some reason, that doesn't work, then you can debug what's doing on by doing this:
const neataptic = require('neataptic');
console.log(neataptic);
And, see what exports there are from that module.
Refer to the following Github issue link to get a solution, Thanks

What does the init command do?

Several Node.js packages have the following two steps as their starting point (just using Jasmine as an example):
npm install --save-dev jasmine
./node_modules/.bin/jasmine init
The first statement is straightforward, but I could not for the life of me figure out what the second statement does under the hood. The Jasmine docs only say that it initializes it (I am searching for something more technical).
./node_modules/.bin/jasmine looks like this:
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../jasmine/bin/jasmine.js" "$#"
ret=$?
else
node "$basedir/../jasmine/bin/jasmine.js" "$#"
ret=$?
fi
exit $ret
In case helpful, I did this to clone and install the package locally:
mkdir testProj : Creates new project folder
code testProj --add : Adds folder to workspace
cd testProj
npm init : Creates package.json
npm install [--save-dev] : Installs dependencies
./node_modules/.bin/ init : What does this do, specifically?
Short: npx init
Any pointers/documentation explaining that init would be deeply appreciated.
Edit:
Just to clarify, I know what init does (clear from testing and the Jasmine documentation), I just do not understand how it does it. I am basically trying to find out why init is needed behind the script name when running it from the CLI, and where the init code is located.
I managed to finally solve this myself. If anyone comes across this in the future, the following is the explanation of ./node_modules/.bin/jasmine init.
./node_modules/.bin/jasmine init is executed from the command line
This runs the jasmine Unix script in ./node_modules/.bin/ (init argument is not used yet)
The script resolves path to jasmine.js (./node_modules/jasmine/bin/jasmine.js) and runs it
Jasmine.js contains this code: var Command = require('../lib/command.js')
Jasmine.js creates a new instance of the Command object (command) and executes: command.run(jasmine, process.argv.slice(2));
process.argv is an array of all arguments given when starting the application from command line. Recalling the command, one sees that slice(2) equals init
The run function inside command.js launches initJasmine by having mapped init to initJasmine at the very top
Finally, initJasmine makes the directory spec and all its contents
Hope that helps someone else in the future.
jasmine init initializes a basic folder structure for Jasmine by creating a spec directory and configuration json for you. You can look for more details here https://github.com/jasmine/jasmine-npm

How to run a command line tool from node.js application

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.

How to pass browserify --require file to angular module?

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.

Categories