Node.js command-line utilities : how to insure module accessibility? - node.js

So, in writing command-line utilities with node, if my command requires certain modules, should I include a package.json file to list those dependencies? Obviously this will require running > npm install on the package file.
Without doing so, packages are not found, even though I've installed them globally. How are others distributing these types of cli scripts?

if my command requires certain modules, should I include a package.json file to list those dependencies?
Yes. This is standard.
Obviously this will require running > npm install on the package file.
This isn't exactly the case. You have to run npm install during development to initialize your environment. However, if someone installs your script through npm (e.g. npm install -g your-script-name), the dependencies for your script will automatically be installed. This is a recursive operation, meaning the dependencies of your dependencies will be installed as well, and so on.

Related

Assigning a command to my NPM Package without installing globally

Some NPM packages are installed into a project, you're then able to run them from your project scripts.
An example of this is webpack-dev-server.
Once installed I just have to add:
"dev": "webpack-dev-server"
In my package.json scripts and it will launch webpack-dev-server.
How does this work? The command isn't globally installed, and yet my Node project knows that it's connected to the package that I have installed.
I've only been able to find information about adding my commands to the bin property within my package's package.json, but that won't work unless the package is installed globally.
How do I achieve this? Is there official documentation somewhere that I haven't been able to find?
you got it right, but you are missing tiny thing...
each package can declare a binary. as you said, this is done in the bin property of the package.json
on install, npm will symlink that file into prefix/bin for global installs, or ./node_modules/.bin/ for local installs.
this is exactly what webpack-dev-server does. its binary is being installed within ./node_modules/.bin/.
due to the convention, npm\npx is able to find the binary and execute it.
in your application, you can utilize this behavior; and any package that will be dependent on your package will be able to execute your package binary.
if you want to provide an argument to the run script, do it like so
npm run webpack-dev-server -- --version

What is the difference between installing a package locally and globally using npm?

What is the difference between installing a package locally and globally using npm?
From my understanding:
Locally install: npm install <package>
This package/module will find on your local node_modules folder and
can only be usable for this project.
This package/module can be accessible in using require("package")
from code.
This package/module can't be accessible in command line interface.
Globally install: npm install <package> -g
This package/module will find on where node is installed in your machine like /usr/local and can be usable everywhere.
This package/module can't be accessible in using require("package")
from code.
This package/module can be accessible in command line interface.
Please let me know. If I could misunderstand anything here. Thanks!
You are correct except for 1 point.
The local packages exposing CLI utilities can be accessed from the command line. Newer versions of NPM create this .bin/ directory inside the local node_modules/.
Whenever you try to use a tool (let's take babel for example), if you use it from the command line and you have it installed in your project, npm will properly identify that package and run it's CLI for you.
Here's a useful article on the topic.
http://www.2ality.com/2016/01/locally-installed-npm-executables.html
Global modules are mostly tools like gulp, yoman or any other module you use in your daily work.
Local modules are the dependencies of your project. You should never depend on a global module in your project. Even dependencies as gulp should be a local dependency in your dev-dependency section.

What does the -g option for npm install and npm list do?

The Node.js npm (Node Package Manager) has a -g command line argument, which I often see referenced. For example, the documentation for the Microsoft Azure x-plat (cross-platform) CLI tool says to install it by using npm install -g azure-cli.
Question: What does the -g option do?
What options do I have to install node modules?
After writing this I quickly found and old but still applicable post by Isaac (yes, the npm #isaacs). But I still think the below post is informational.
You can install npm modules globally or locally - you already know that, but why?
Globally: npm install -g some-module-a: This module is intended to be used as an executable (i.e. CLI, file watcher, code minifier, logger, etc.).
Locally: npm install some-module-b: To be imported and used in your app via import, var someModule = require('some-module)
global modules are one of the best ideas of npm. We can easily create executables using node/javascript. If your node app is meant to be run as an executable, then you will want others to install it globally. If it's a utility, helper, application, etc. then you usually don't want it installed globally. So, unless the module explicitly states that you should install it with -g, then don't.
One more time: if you are wanting to use some module called some-module in your node app - var someModule = require('some-module'), then npm install some-module from the root of your node app to pull it into your local node_modules directory. If you've installed some-module globally and not locally, it will usually not load and will show you an error about not finding the module (even though it can be made to load the global module - hint: just don't!)
So what exactly happens when you install globally?
npm install -g [some module] installs the specified node module in a directory higher up in your file system (i.e. usually /usr/local/lib/node_modules in unix systems). The biggest use case for global modules is for CLIs written using node (think npm, bower, gulp, grunt, et. al.).
Let's look at what happens when you install bower globally:
*follow these steps in your command line/terminal
step: npm install -g bower
explanation: the module - all of it's files and dependencies - are saved in your global directory (e.g. /usr/local/lib/node_modules/bower).
Something else happened here. Somehow you can now run bower in your command line. Awesome!
step: bower -v --> results in the installed bower version (i.e. 1.6.5)
explanation: It's now a fully executable node app using bower as the keyword. Inside bower's package.json file you'll find a bin property:
"bin": {
"bower": "bin/bower"
}
So how did that all work?
npm will create a symlink from where most executables live, /usr/local/bin/bower over to /usr/local/lib/node_modules/bower/bin/bower, where the module lives. That symlink makes it so when the executable runs, it can reference other files in the original module, including it's local node_modules. Pretty cool, huh?
*Note on executables: If you create a file called awesomeness in /usr/local/bin/ and chmod u+x (user + executable) it. Then write some scripting in it (in this case javascript using #!/usr/bin/env node at the top). Then you can run it anywhere in your command line/terminal just by typing awesomeness.
Hope that helped. I know doing a deeper dive into it helped me early on.
Node.js packages can be installed one of two ways:
Globally
Locally
The -g option instructs npm to install the package globally. You would install a Node.js package globally, if you want to be able to call the command directly from the terminal.
From the documentation:
There are two ways to install npm packages: locally or globally. You choose which kind of installation to use based on how you want to use the package.
If you want to use it as a command line tool, something like the grunt CLI, then you can want to install it globally. On the other hand, if you want to depend on the package from your own module using something like Node's require, then you want to install locally.
To download packages globally, you simply use the command npm install -g , e.g.:

Locally installed versus globally installed NPM modules

In my package.json file, I have bower listed as a dependency. After I run npm install, bower gets installed locally. When I try to run bower after installing it locally I get an error
"bower" is not recognized as an internal or external command
It seems the only way to resolve this is to install bower globally. Why should I have to do this? If my project contains a local copy of bower, why won't node use it?
Installing locally makes bower available to the current project (where it stores all of the node modules in node_modules). This is usually only good for using a module like so var module = require('module'); It will not be available as a command that the shell can resolve until you install it globally npm install -g module where npm will install it in a place where your path variable will resolve this command.
Edit: This documentation explains it pretty thorougly.
You can execute your local instance by typing the line below in cmd:
node_modules/bower/bin/bower <bower args>
We use both PHP and JavaScript, so we have composer and npm.
Each of the projects we work on have different packages both for runtime of the package as well as build/dev tools.
As there are version constraints in each project, installing version x of a package globally (that would be run from the command line), would cause us issues, we install all the tooling in each package. Much easier to define in the appropriate composer.json / package.json files.
But running the CLI tools is a pain if you have to constantly add an additional path to the command.
To that end, we have recommend to the team that the following paths are added to your $PATH in the appropriate .bashrc (or equivalent):
./vendor/bin:./node_modules/.bin
(EDIT: For Windows, the paths would be .\vendor\bin;.\node_modules\.bin;)
So, whilst in project X, we have access to the CLI tools for that project. Switch to project Y, and we get that projects tools.
Sure, you are going to get duplications, but each project is maintained by different teams (and some people are in multiple teams), so again, having 1 version in the global setup is an issue there.
Usually you install NPM modules globally if you want them included in your path to be ran from the command line. Since it is installed locally you will have to run it from the node_modules folder.

What does "npm install -g" do?

I am trying to install Less from NPM by running npm install -g less in the command line. I checked the docs for the install command:
In global mode (ie, with -g or --global appended to the command), it
installs the current package context (ie, the current working
directory) as a global package.
What does it mean by "global package"?
You are not required to install Less globally.
Installing it locally means the module will be available only for a specific project (the directory you were in when you ran npm install), as it installs to the local node_modules folder.
A global install will instead put the module into your global package folder (OS dependent), and allows you to run the included executable commands from anywhere. Note that by default you can only require local packages in your code.
See the node.js docs for more info on global vs local packages.
Generally speaking, you should install most modules locally, unless they provide a CLI command that you want to use anywhere.
In the end, I suggest you install less globally, as less provides an executable command that you will likely need in different projects. This is also what the Less docs recommend.
From: https://nodejs.org/en/blog/npm/npm-1-0-global-vs-local-installation/
There are two ways to install npm packages:
globally —- This drops modules in {prefix}/lib/node_modules, and puts executable files in {prefix}/bin, where {prefix} is usually something like /usr/local. It also installs man pages in {prefix}/share/man, if they’re supplied.
locally —- This installs your package in the current working directory. Node modules go in ./node_modules, executables go in ./node_modules/.bin/, and man pages aren’t installed at all.
It simply means that the package you are installing while be available/integrated throughout your Nodejs platform.

Resources