NPM: Change the `bin` output directory for the node modules - node.js

Currently, if you are using a package.json file to manage your project's dependencies (whatever project it is, may it be a ruby, php, python or js app), by default everything is installed under ./node_modules.
When some dependencies have binaries to save, they're installed under ./node_modules/.bin.
What I need is a feature that allow me to change the ./node_modules/.bin directory for ./bin.
Simple example:
A PHP/Symfony app has a ./vendor dir for Composer dependencies, and all binaries are saved in ./bin, thanks to the config: { bin-dir: bin } option in composer.json.
But if I want to use Gulp to manage my assets, I create a package.json file, require all my dependencies and then run npm install.
Then, my wish is to run bin/gulp to execute gulp, but actually I have to run node_modules/.bin/gulp which is not as friendly as bin/gulp.
I've looked at package.json examples/guides on browsenpm.org and docs.npmjs.com, but none of them works, because they are here to define your own project's binaries. But I don't have any binaries, because I want to use binaries from other libraries.
Is there an option for that with NodeJS/NPM ?

You might consider adding gulp tasks to your package.json.
// package.json
{
"scripts": {
"build-templates": "gulp build-templates",
"minify-js": "gulp minify-js"
}
}
You can run any scripts specified in package.json by simply running the following:
$ npm run build-templates
$ npm run minify-js
You get the idea. You can use the gulp command inside the string without doing ./node_modules/.bin/gulp because npm is smart enough to put all scripts from ./node_modules/.bin/ into the path for that script execution.

Related

What's the difference between "npm install -g" (no args) and "npm link" to create CLI command?

To make a local node.js package work as a global commandline tool, I first add this to package.json
"bin": {
"myCommand": "./index.js"
}
According to the npm docs, I then have two options:
Within that folder, run npm install -g. According to the node docs:
npm install (in package directory, no arguments) ... In global mode
... installs the current package context (ie, the current working
directory) as a global package.
OR
Within that folder, run npm link. The node docs say
npm link in a package folder will create a symlink in the global
folder ... will also link any bins in the package to
{prefix}/bin/{name}
Both of these routes lets me run myCommand anywhere in the terminal while local edits are reflected in the tool without reinstalling/linking.
For local CLI tool purposes, these commands seem functionally identical. Is this true? Why would I want to use npm install -g (no args) when npm link seems functionally identical, plus affording extra capability?
Note: this question is purely about a local node project, nothing to do with anything in a remote package registry

How to make npm scripts refer to local packages?

I am working on a project and I want to use JSdoc for documentation. I have listed it in devDependencies and created a script to run it. My package.jsonlooks like:
"scripts": {
"doc": "jsdoc -c ./conf.json"
},
"devDependencies": {
"jsdoc": "^3.4.3"
}
Cloning my project on another machine and typing npm install installs jsdoc to the node_modules folder.
However, when I run npm run doc, I get a large error, the center of which is: 'jsdoc' is not recognized as an internal or external command
This is because JSdoc is installed in node_modules not my local path.
What is the best way to point npm-run commands to my locally installed modules? Also, what is the point of having dependencies such as JSdoc listed in devDependencies (thus installed in node_modules) when they can not be used from there?

Locally installed gulp not running in command line?

I am new to nodejs and gulp stuff. I working on a nodejs project in which I have to run jslint on all the files. I am using gulp for this purpose.
My problem is that In order to run gulp on cli I don't want to install gulp globally and also does not want to update my path variable, So I have installed gulp and other node modules in my project locally using the package.json file
cd myproject
npm install
Since I don't want to install gulp globally and want to run the local gulp I have added script in my package.json file like this as given in this question
{
"name": "",
"version": "1.0.0",
"main": "index.js",
"private": true,
"dependencies": {
"async": "1.5.0"
},
"devDependencies": {
"gulp": "^3.9.0",
"gulp-jslint": "^0.2.2"
},
"scripts": {
"gulp": "./node_modules/.bin/gulp" // is this correct?
}
}
Add added a gulpfile.js inside my myproject folder
var gulp = require('gulp');
// include plug-ins
var jslint = require('gulp-jslint');
// JS hint task
gulp.task('lint', function() {
gulp.src('./common/srp/*.js')
.pipe(jslint())
.pipe(jslint.reporter('default'));
});
gulp.task("default", ["lint"]);
But now on my command line inside myproject folder, when I run gulp and gulp lint I get an error
user1-VirtualBox:~/myproject$ gulp lint
/usr/local/node-v0.10.26-linux-x64/bin/gulp No such file or
directory
Its looking for gulp in the global node module.
Is there a way to make gulp run on cli without installing globally and updating PATH variable.
Any help will be appreciated
Thanks
You can find any executable installed by npm in node_modules/.bin. So you can run gulp locally using:
./node_modules/.bin/gulp
You can find more information at no command 'gulp' found - after installation
With your code you should be able to run command
npm run gulp
Please try
One way to define script is
"scripts": {
"gulp": "gulp"
}
If in case you are not able to run gulp command in your project, run
npm link gulp
It will link your global install gulp with your local project. Then try
gulp -v
If it is showing you the version then you are done. Now you can run any gulp command as you want.
Scripts defined in package.json are accessed through NPM, i.e. npm run-script gulp. I imagine you're trying to run plain old gulp, which should fail since you didn't install it globally.
The scripts section won't automatically create an alias, which I think is your mistake here. You could define one yourself or create a simple bash script if you don't want to type it every time.
Try:
path_to_node path_to_gulp_js gulp_task
Example:
node\node.exe node_modules\gulp\bin\gulp.js build
Like #snorberhuis said. The only way for me to get gulp to work globally was to call gulp manually
I am building in a Jenkins environment
Execute Windows Batch Command
cd your-app
npm install gulp
Execute Windows Batch Command
cd your-app\node_modules\.bin
gulp
Just another alternative that will work locally but will give you global like feeling.
Add to your shell config i.e. ~/.bash_profile the following
export PATH=$PATH:./node_modules/.bin
you have to source that file, execute rehash or just open a new shell and then gulp (and any other script inside that folder) shall be available as a global command.
The way I did this after bashing my head every possible place is simply going to your Application and install npm dependencies like this:
1- E:\webra-jenkins\Code\trunk\WebRa.Web>npm install
Once npm installed then go this directory
2- [%Application_path%]\node_modules\.bin
And execute the gulp and give your file/task, like this:
3-[%Application_path%]\node_modules\.bin>gulp gulpfile --tasks
In my case as I saw the following lines... I got the inner happiness
18:06:36] Working directory changed to [%Application_path%]
[18:06:37] Tasks for [%Application_path%]\gulpfile.js
Now you can run your tasks 1 by one.
[%Application_path%]\node_modules\.bin>gulp pack-vendor-js
Check in your project node_modules/.bin folder and make sure gulp is in there. I had a case where it wasn't there that I never tracked down the reason for. If it isn't there, try re-installing gulp locally and see if it shows up. If that doesn't work and you get tired of the problem, the gulp-cli package will fix it for sure, but that shouldn't be something you have to do.
The simplest solution I know of is to use npm bin:
`npm bin`/gulp ...
This keeps you away from hard-coding any paths.
Nothing was working for me. I followed all instructions from everyone. No matter what I did I could not run the Gulp commands.
To fix this I opened the Node.js command prompt that comes installed automatically when you download and run node.js.
Once I was in this command prompt I could run the following commands:
npm install -g gulp
gulp -v
This is probably a matter of common knowledge but as someone starting out no one suggested to run the node.js command prompt and install gulp from there. Everything I read talked about regular powershell or command prompts with elevated permissions.
Globally install gulp in C:\Users\%USERNAME% using this command
npm install –g gulp
You can install any other gulp methods you need to use.. Ex:
npm install -g gulp-concat
npm install -g gulp-uglify
npm install -g gulp-replace
Then at the directory you wish to use GULP. Open the command prompt (Shift + RightClick) then install locally and you'll be able to execute gulp.
npm install gulp
You can install any other gulp methods you need to use.. Ex:
npm install gulp-concat
npm install gulp-uglify
npm install gulp-replace

Locally-installed cli NPM project that is easy to execute

I'm building a cli node module. I would like people to be able to npm install it and use it right away with a command like npm my-project --arg=foo. It's meant for local project CLI use as a dev tool, not global installation.
It seems like the standard is to use bin in the package.json, but I don't understand some things about it:
When should I use bin and when should I use scripts?
How to I run the command in the including project? npm my-project doesn't do it.
Here is what I am doing now in package.json:
{
"name": "my-project",
"bin": "./cli.js"
}
And I can run it locally:
node cli.js --arg=foo
But when I npm-install my-project somewhere else, I don't know how to run the script it puts in bin (npm run my-project doesn't work), or if I'm using this correctly.
Let's start by explaining the difference between bin and scripts: the former you use if you want to provide a command line tool, the latter you use if you want to provide an additional command to npm (with some caveats though, see below).
In your situation, I think you want to use bin. However, instead of the user using npm my-project --arg=foo, they will use my-project --arg=foo, provided that your script is called my-project. To make that happen, your package.json will contain something like this:
"bin" : "./bin/my-project"
During installation, this will copy ./bin/my-project to a "bin" directory (usually /usr/local/bin on Unix-like OS'es). During development, you can call it as node bin/my-project, or even just ./bin/my-project, provided that it has correct permissions and "shebang".
EDIT: so I forgot that npm will use the package name, and not the name of the file in ./bin, as the executable name (if bin is a string). If your package is called my-project, and you install the package (you need to use the -g flag before npm will install the executable), it will create an executable called my-project, regardless of where the bin property points to.
In other words:
package.json:
"name" : "my-project"
"bin" : "./cli.js"
npm install -g:
copies ./cli.js to /usr/local/bin/my-project and sets executable permissions
END EDIT
FWIW, storing CLI tools in ./bin is convention, but not mandatory.
The scripts directive is useful for more internal purposes. For instance, you can use it to run a test suite, or linters, or pre/post install scripts.
Lastly, there are various modules available to help with command line parsing. I like docopt, but other often-used modules are commander or nomnom. You already mentioned yargs.

Installing "global" npm dependencies via package.json [duplicate]

This question already has answers here:
Install dependencies globally and locally using package.json
(7 answers)
Closed 8 years ago.
I have a few "global" dependencies (jshint, csslint, buster, etc..) that I'd like to have automatically installed and executable via the command line when my package is installed via npm install. Is this possible?
Currently, I'm doing the following manually:
npm install -g <package_name>
from within my project: npm link <package_name>
Update:
Just came across this feature request for npm. It seems like the scripts config within package.json is the way to go?
Update Again:
Or, after reading the npm docs, maybe I'm supposed to use a .gyp file? I'm confused.
It's not possible to specify dependencies as "global" from a package.json. And, this is by design as Isaac states in that feature request you referenced:
Yeah, we're never going to do this.
But, "binaries" can still be used when a package is installed locally. They'll be in .../node_modules/.bin/. And, you should be able to queue them up with a preinstall script.
Though, if the series of commands is rather lengthy (as "jshint, csslint, buster, etc.." would suggest), you may want to look into using a build tool such as grunt to perform the various tasks:
{
// ...,
"scripts": {
"preinstall": "grunt"
}
}
I really like the pattern where you install local dependencies, then use a bash script that sets your PATH to ./node_modules/.bin.
File: env.sh
# Add your local node_modules bin to the path for this command
export PATH="./node_modules/.bin:$PATH"
# execute the rest of the command
exec "$#"
Then, you can use this script before any bash command. If you pair that with a Makefile or npm script:
File: Makefile
lint :
./env.sh csslint my_styles
File: package.json
"scripts": {
"lint": "./env.sh csslint my_styles"
}
This tasks in these files look like they reference csslint in some global location, but they actually use the version in your node_modules bin.
The really awesome benefit of this is that these dependencies can be versioned easily, just like your other node modules. If you stick with a global install solution, you could be clobbering some specific version on the user's system that is required for one of their other projects.
You should try this: https://github.com/lastboy/package-script
I've been using it to install global npm packages straight from the package.json. It works well for clients who aren't technically literate.
It even checks if the packages are already installed, if not install them!

Resources