Note. This answer relates to a specific use case for OP: calling CLI dependent packages in the context of this project; it's not about making the CLI globally accessible - see the bottom for a discussion.
TL; DR:
On Unix-like platforms , add npm run env -- to your command ; eg:.
npm run env -- mocha --recursive test*.js --compilers js:babel-register
This not only allows you to invoke dependent CLIs with a simple name, but completely replicates the environment in which npm installs behind the scenes using npm test or npm run-script <script-defined-in-package.json> .
Unfortunately, this approach does not work on Windows.
Windows solutions use convenience aliases (including half-session environment configuration commands) and help information.
There are two (not mutually exclusive) approaches for creating CLI dependencies of npm project dependencies on a simple name from the shell :
- (a) Use a command for each call that you pass to commands .
- (b) Run the command once per session, which (temporarily) changes your environment .
The helpful answer Frxstrem provides an incomplete solution for (a) on Unix-like platforms; it may, however, be sufficient, depending on your specific needs.
It is incomplete in that it simply adds a directory containing (symbolic links) dependent CLIs to $PATH , without performing all other environment modifications that occur when calling npm test or npm run-script <script-defined-in-package.json .
Unix Convenience and Windows Solutions
Please note that all of the solutions below are based on npm run env , which ensures that all the necessary environment variables are set in the same way as when your startup scripts are predefined in the package.json project file with npm test or npm run-script <script> .
These environmental changes include:
- Prepending
$(npm prefix -g)/node_modules/npm/bin/node-gyp-bin and a subdirectory of the project directory ./node_modules/.bin , which contains symbolic links to dependency ./node_modules/.bin (temporarily) with the $PATH environment variable. - Defining numerous
npm_* environment variables that reflect project parameters, such as npm_package_version , as well as npm / node environment.
Convenient solutions for Unix-like platforms:
Both solutions are below with an alias , which in case (a) is an easier alternative to using a script, and in case (b) there is a prerequisite that allows you to change the current shell environment (although you can use the shell function).
For convenience, add these aliases to your profile / shell initialization file .
(a) Auxiliary Assistant:
Definition
alias nx='npm run-script env --'
allows you to call your ad-hoc commands simply by adding nx ; eg:.
nx mocha --recursive test/**/*.js --compilers js:babel-register
(b) Post-session configuration command:
alias npmenv='npm run env -- $SHELL'
Run npmenv to enter a child shell with a set of npm environments, allowing direct (by name only) invocation of the dependent CLIs in that child shell.
In other words, use it as follows:
cd ~/some-npm-project npmenv
Windows Solutions:
(a) and (b) . Please note that Windows (unlike shells similar to POSIX on Unix-like platforms) does not support (directly) the transfer of environment variables that are bound to only one command, therefore the following commands, even when specific commands are executed for execution (case (a) ) invariably also change the session environment (case (b)).
PowerShell (also works on Unix versions):
Add the following function to your $PROFILE (user profile script):
function npmenv($commandIfAny) { npm run env -- | ? { $_ -and $_ -notmatch '^>' -and $_ -match '^[a-z_][a-z0-9_]+=' } | % { $name, $val = $_ -split '='; set-item -path "env:$name" -value $val } if ($?) { if ($commandIfAny) { & $commandIfAny $Args } } }
cmd.exe (regular command line, often mistakenly called the "DOS prompt"):
Create a batch file named npmenv.cmd , put it in a folder in %PATH% and define it as follows:
@echo off :: Set all environment variables that `npm run env` reports. for /f "delims==; tokens=1,*" %%i in ('npm run env ^| findstr /v "^>"') do set "%%i=%%j" :: Invoke a specified command, if any. %*
Usage (both cmd.exe and PowerShell):
In the case of using (b), just call npmenv with no arguments; after that you can call the dependent CLIs with a simple name ( mocha ... ).
In the case of using (a), preend npmenv to your team; eg:.
npmenv mocha --recursive test/**/*.js --compilers js:babel-register
Warning. As noted, the first npmenv — with or without arguments — invariably changes the %PATH% / $env:PATH variable for the remainder of the session.
If you switch to another project in the same session, be sure to run npmenv (at least once) again, but note that this adds additional directories to %PATH% , so you can still accidentally run the previous executable project, if it is not an established dependence on the current project.
From PowerShell, you could actually combine the two solutions to get excellent (a) and (b) functionality: define the *.cmd file above as a separate command (using a different name, for example nx.cmd ), which you only use with arguments (a) and override the PowerShell function to serve as a complement to the complement without changing the arguments (b).
This works because PowerShell invariably runs *.cmd files in a child process that cannot affect the current PowerShell session environment.
Notes on the scope of the question and answer:
The OP question is to call the CLI of already installed dependent packages in the context of this ad-hoc project, by the simple name of the executable file - just like npm allows you to execute commands added to scripts in the package.json file.
The issue is not to make CLIs available worldwide (by installing them using npm install -g ).
In fact, if you want to create modular, stand-alone packages, they do not depend on packages installed globally. Instead, make all dependent packages part of your project: use npm install --save (for run-time dependencies) and npm install --save-dev (for development-time dependencies) - see https://docs.npmjs.com/ cli / install
In particular, if the specified CLI is already installed as a dependency, installing it globally (potentially a different version) is not only redundant, but it also confuses which version is executed when.