How do I use a local version of a module in node.js
. For example, in my app, I installed coffee-script:
npm install coffee-script
Use npm run[-script] <script name>
After using npm to install the bin package to your local ./node_modules
directory, modify package.json
to add <script name>
like this:
$ npm install --save learnyounode
$ edit packages.json
>>> in packages.json
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"learnyounode": "learnyounode"
},
...
$ npm run learnyounode
It would be nice if npm install had a --add-script option or something or if npm run would work without adding to the scripts block.
Add this script to your .bashrc
. Then you can call coffee
or anyhting locally. This is handy for your laptop, but don't use it on your server.
DEFAULT_PATH=$PATH;
add_local_node_modules_to_path(){
NODE_MODULES='./node_modules/.bin';
if [ -d $NODE_MODULES ]; then
PATH=$DEFAULT_PATH:$NODE_MODULES;
else
PATH=$DEFAULT_PATH;
fi
}
cd () {
builtin cd "$@";
add_local_node_modules_to_path;
}
add_local_node_modules_to_path;
note: this script makes aliase of cd
command, and after each call of cd
it checks node_modules/.bin
and add it to your $PATH
.
note2: you can change the third line to NODE_MODULES=$(npm bin);
. But that would make cd
command too slow.
I prefer to not rely on shell aliases or another package.
Adding a simple line to scripts
section of your package.json
, you can run local npm commands like
npm run webpack
package.json
{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack"
},
"devDependencies": {
"webpack": "^4.1.1",
"webpack-cli": "^2.0.11"
}
}
If you want your PATH variable to correctly update based on your current working directory, add this to the end of your .bashrc
-equivalent (or after anything that defines PATH
):
__OLD_PATH=$PATH
function updatePATHForNPM() {
export PATH=$(npm bin):$__OLD_PATH
}
function node-mode() {
PROMPT_COMMAND=updatePATHForNPM
}
function node-mode-off() {
unset PROMPT_COMMAND
PATH=$__OLD_PATH
}
# Uncomment to enable node-mode by default:
# node-mode
This may add a short delay every time the bash prompt gets rendered (depending on the size of your project, most likely), so it's disabled by default.
You can enable and disable it within your terminal by running node-mode
and node-mode-off
, respectively.
I'd love to know if this is an insecure/bad idea, but after thinking about it a bit I don't see an issue here:
Modifying Linus's insecure solution to add it to the end, using npm bin
to find the directory, and making the script only call npm bin
when a package.json
is present in a parent (for speed), this is what I came up with for zsh
:
find-up () {
path=$(pwd)
while [[ "$path" != "" && ! -e "$path/$1" ]]; do
path=${path%/*}
done
echo "$path"
}
precmd() {
if [ "$(find-up package.json)" != "" ]; then
new_bin=$(npm bin)
if [ "$NODE_MODULES_PATH" != "$new_bin" ]; then
export PATH=${PATH%:$NODE_MODULES_PATH}:$new_bin
export NODE_MODULES_PATH=$new_bin
fi
else
if [ "$NODE_MODULES_PATH" != "" ]; then
export PATH=${PATH%:$NODE_MODULES_PATH}
export NODE_MODULES_PATH=""
fi
fi
}
For bash
, instead of using the precmd
hook, you can use the $PROMPT_COMMAND
variable (I haven't tested this but you get the idea):
__add-node-to-path() {
if [ "$(find-up package.json)" != "" ]; then
new_bin=$(npm bin)
if [ "$NODE_MODULES_PATH" != "$new_bin" ]; then
export PATH=${PATH%:$NODE_MODULES_PATH}:$new_bin
export NODE_MODULES_PATH=$new_bin
fi
else
if [ "$NODE_MODULES_PATH" != "" ]; then
export PATH=${PATH%:$NODE_MODULES_PATH}
export NODE_MODULES_PATH=""
fi
fi
}
export PROMPT_COMMAND="__add-node-to-path"
The PATH solution has the issue that if $(npm bin) is placed in your .profile/.bashrc/etc it is evaluated once and is forever set to whichever directory the path was first evaluated in. If instead you modify the current path then every time you run the script your path will grow.
To get around these issues, I create a function and used that. It doesn't modify your environment and is simple to use:
function npm-exec {
$(npm bin)/$@
}
This can then be used like this without making any changes to your environment:
npm-exec r.js <args>