NPM package - add a script to the consumer's node_modules/.bin - node.js

I'm crafting a npm package.
I want to expose a script to the consumer as soon as the package is installed, much like Typescript's tsc.
How do I do it?

Add something similar as below to your package.json:
"bin": {
"router": "dist/src/bin/router.js"
}
This will create a symlink named router in the bin folder pointing to router.js.
Read more about bin here

Related

Create pseudo node_modules folder on npm install

I updated some libraries within my project and now I get an issue with the zlib within ng2-pdf-viewer.
There is also an issue created on github, that helped to fix it for now:
https://github.com/VadimDez/ng2-pdf-viewer/issues/322#issuecomment-389281242
The solution suggests to create a zlib folder within node_modules and add an empty index.js and a basic package.json.
This fixed the issue. But now I want to automate the process, since every time anyone runs npm install the pseudo folder is gone again.
Is there any way to create this folder with it's content automatically on npm install (maybe with mkdir or something)?
PS: The solution to put "browser": { "zlib": false } into the package.json didn't help in my case...
You should be able to create a script to create the directory, and then use a hook to run that script after you run npm install:
"scripts": {
"postinstall": "myCustomScriptToCreateFolder",
},
More reading:
npm Scripts Documentation
StackOverflow Post about this sort of thing

Package and distribute Bash script with NPM to allow installation globally into developer workstation's paths with npm install

I have some scripts that I want to distribute with npm for developers to be able to install globally on their workstations and then use the commands of the scripts on their computers in their development workflow.
I can't work out how to get npm to actually add the script in its package to the path though.
I see that the firebase tools have this in their package.json:
"preferGlobal": true,
"bin": {
"firebase": "./bin/firebase"
},
...but I can't quite work out how this relates to my project.
The first project I am trying to distribute with npm is for controlling a Belkin WeMo light switch, it includes an executable 'wemo' and an included functions.inc.sh file, this can be seen # https://github.com/agilemation/Belkin-WeMo-Command-Line-Tools.git
If anyone can point me in the right direction it will be really appreciated!!!
Thanks,
James
Any key/value pairs placed into the bin key of the package.json will be symlink'ed into the NPM bin-dir path.
The key is what you want the command to be named and the value part is the script in your package it should run.
Ergo, in your example, when npm install finishes running it'll create a symlink from [package-install-path]/bin/firebase to /usr/local/bin/firebase (or whatever bin directory prefix NPM is using (npm bin -g will tell you where this is).
If you only have one script you can also do:
{
"name": "my-awesome-package",
"bin": "./myscript.sh"
}
And it'll symlink myscript.sh to my-awesome-package
Although you should be wary of including bash scripts since they won't work on Windows.
Here are the docs for this.

How to reconcile global webpack install and local loaders

My package.json includes webpack and some loaders:
"devDependencies": {
"babel-core": "^5.2.17",
"babel-loader": "^5.0.0",
"jsx-loader": "^0.13.2",
"node-libs-browser": "^0.5.0",
"webpack": "^1.9.4"
}
When I run webpack it's not in my path so it doesn't show as found. I installed it globally npm install -g webpack so the binary would appear in my path, but then it can't find the loader modules that were installed in ./node_modules that it needs to process my dependency tree:
$ webpack --progress --colors --watch
10% 0/1 build modules/usr/local/lib/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:206
throw e;
^
Error: Cannot find module 'jstransform/simple'```
What is the preferred solution here?
I can install my loaders globally, but I don't like that because of cross-project issues
I can try to run webpack out of node_modules (not sure how to be honest, add it to $PATH for every project?)
Or I can try to give my global webpack access to my node_modules folder, which also seems hacky.
Have I done something wrong, or is there a better community-approved way around this maybe common problem?
I have a blog post called Managing Per-Project Interpreters and the PATH that details my methodology for this. I'll summarize here to address some of your key questions.
What is the preferred solution here?
Never (really, literally never) use npm -g. Just install normally within your project. Use your shell to set the PATH appropriately. I use zsh to do this automatically as detailed in the blog post above so if I cd into a project with ./node_modules/.bin, it gets put on my PATH automatically.
There are other ways that work including making aliases like alias webpack="./node_modules/.bin/webpack" and so on. But really just embrace changing your PATH and you'll have the most harmonious long-term experience. The needs of a multiproject developer are not met by old school unix everything lives in either /bin or /usr/bin.
If you use npm scripts (the "scripts" key in your package.json), npm automatically includes ./node_modules/.bin in your PATH during those scripts so you can just run commands and they will be found. So make use of npm scripts and if you make use of shell scripts that's an easy place to just do export PATH="$PWD/node_modules/.bin:$PATH".
Any binaries that come with packages defined in your dependencies should be placed under ./node_modules/.bin, so you should be able to access there, i.e.: ./node_modules/.bin/webpack.
Alternatively, you could define a script inside your package.json, which would allow you to run something like npm run webpack as an alias.

NPM: Change the `bin` output directory for the node modules

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.

Install a locally developed npm package globally

I'm developing a node package that needs to be run from shell. I know I have to install the package globally, but running
$> npm install -g ./my_module
Does not give me the desired result, that is running
$> my_module
Results in
my_module: : command not found
Instead of running the entry point (index.js) of my node package.
I feel like I'm missing something obvious in here, what am I doing wrong?
After setting up the right package.json configuration, (mainly using {"bin": {...}}), You don't have to publish it to NPM registry then download it again to see it working.
npm link made exactly for this situations. as described in the offical documentation:
npm link in a package folder will create a symlink in the global folder {prefix}/lib/node_modules/ that links to the package where the npm link command was executed.
Assuming you have this project:
-- my_module
-- -- index.js
-- -- cli.js
-- -- package.json
and you have this package.json:
{
"name": "my_module",
"bin": {
"my_module": "cli.js"
},
}
Run:
cd my_module
Then:
npm link
Now npm will install your package globally in your machine. it will check the package.json for the bin entry, and it will link my_module to the cli.js file. This will happen by creating a symlink in the global npm directory to your current directory.
now if you run in your command line:
my_module
it will point to the cli.js file. if you changed cli.js contents, it will be reflected the next time you run my_module, if you renamed my_module to my_module2, use npm unlink then npm link again.
On a different note, npm can use a full url as a package name, it will use the full url to download and install the package instead of looking at the npm registry, you can install packages from your own private Git hosts, for example:
npm install -g https://github.com/Me/my_module
Please try to pack the module and install.
npm pack
and then install it globally
npm i -g my_module-0.0.1.tgz
Let me know is this worked or not
I faced the same issue recently. I developed my module as a CLI with the intent to be able to invoke it from anywhere, published it to the NPM registry and installed it using the -g option but when calling it from the command line I was still getting the command not found error. Adding the bin attribute to the package.json file is what did the trick.
From the NPM documentation:
A lot of packages have one or more executable files that they’d like to install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the “npm” executable.)
To use this, supply a bin field in your package.json which is a map of command name to local file name. On install, npm will symlink that file into prefix/bin for global installs, or ./node_modules/.bin/ for local installs.
Meaning your package.json file should look like this:
{
"name": "foo-cli",
"version": "1.0.0",
"description": "A CLI to do Foo-ish things.",
"bin": {
"foo": "./cli.js"
},
"main": "main.js",
...
}
The property can be a single string if you only wish to specify one single command, or a map if you wish to specify many. Now you should be able to call foo from anywhere in the command line.

Resources