Как использовать пакет, установленный локально в node_modules?

StackOverflow https://stackoverflow.com//questions/9679932

Вопрос

Как мне использовать локальную версию модуля в node.js.Например, в моем приложении я установил coffee-script:

npm install coffee-script

Это устанавливает его в ./node_modules и команда "кофе" находится в ./node_modules/.bin/coffee.Есть ли способ запустить эту команду, когда я нахожусь в основной папке моего проекта?Наверное, я ищу что-то похожее на bundle exec в пакете.В принципе, я хотел бы указать версию coffee-script, которую должны использовать все участники проекта.

Я знаю, что могу добавить -g отметьте, чтобы установить его глобально, чтобы coffee нормально работал где угодно, но что, если я захочу иметь разные версии coffee для каждого проекта?

Это было полезно?

Решение

ОБНОВЛЕНИЕ:Как указывает Сеен Чжон в своем ответе ниже, начиная с npm 5.2.0, вы можете использовать npx [command], что более удобно.

СТАРЫЙ ОТВЕТ для версий до 5.2.0:

Проблема с размещением

./node_modules/.bin

в вашем PATH заключается в том, что он работает только тогда, когда ваш текущий рабочий каталог является корневым в структуре каталогов вашего проекта (т.е.местонахождение node_modules)

Независимо от того, каков ваш рабочий каталог, вы можете получить путь к локально установленным двоичным файлам с помощью

npm bin

Для выполнения локально установленного coffee двоичный файл независимо от того, где вы находитесь в иерархии каталогов проекта, вы можете использовать эту конструкцию bash

PATH=$(npm bin):$PATH coffee

Я присвоил этому псевдониму значение npm-exec

alias npm-exec='PATH=$(npm bin):$PATH'

Итак, теперь я могу

npm-exec coffee

чтобы запустить правильную копию coffee, независимо от того, где я нахожусь

$ pwd
/Users/regular/project1

$ npm-exec which coffee
/Users/regular/project1/node_modules/.bin/coffee

$ cd lib/
$ npm-exec which coffee
/Users/regular/project1/node_modules/.bin/coffee

$ cd ~/project2
$ npm-exec which coffee
/Users/regular/project2/node_modules/.bin/coffee

Другие советы

Nice example

Вам не нужно манипулировать $PATH больше!

От НПМ@5.2.0, НПМ корабли с npx пакет, который позволяет запускать команды из локального node_modules/.bin или из центрального кэша.

Просто запустите:

$ npx [options] <command>[@version] [command-arg]...

По умолчанию, npx проверю, есть ли <command> существует в $PATH, или в двоичных файлах локального проекта и выполните это.

Вызов npx <command> когда <command> еще нет в вашем $PATH автоматически установит для вас пакет с таким именем из реестра NPM и вызовет его.Когда это будет сделано, установленный пакет не будет нигде в ваших глобальных файлах, поэтому вам не придется беспокоиться о загрязнении в долгосрочной перспективе.Вы можете предотвратить такое поведение, предоставив --no-install вариант.

Для npm < 5.2.0, вы можете установить npx пакет вручную, выполнив следующую команду:

$ npm install -g npx

Используйте команду npm bin, чтобы получить модули узлов / каталог Bin вашего проекта

$ $(npm bin)/<binary-name> [args]
.

e.g.

$ $(npm bin)/bower install
.

Воспользуйся npm run[-script] <script name>

После использования npm для установки пакета bin на ваш локальный ./node_modules каталог, изменить package.json добавить <script name> подобный этому:

$ npm install --save learnyounode
$ edit packages.json
>>> in packages.json
...
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "learnyounode": "learnyounode"
},
...
$ npm run learnyounode

Было бы неплохо, если бы в npm install была опция --add-script или что-то в этом роде, или если бы npm run работал без добавления в блок scripts.

Используйте npm-run .

из readme:

NPM-Run

Найти и запустить локальные исполнители от Node_Modules

Любой исполняемый файл, доступный для сценария жизненного цикла NPM, доступен для npm-run.

Использование

$ npm install mocha # mocha installed in ./node_modules
$ npm-run mocha test/* # uses locally installed mocha executable 
.

Установка

$ npm install -g npm-run
.

Обновление: Я больше не рекомендую этот метод, как по упомянутым соображениям безопасности, так и не в последнюю очередь по более новым npm bin команда.Оригинальный ответ ниже:

Как вы уже выяснили, все локально установленные двоичные файлы находятся в ./node_modules/.bin.Чтобы всегда запускать двоичные файлы в этом каталоге, а не в глобально доступных двоичных файлах, если таковые имеются, я предлагаю вам установить ./node_modules/.bin первый на твоем пути:

export PATH="./node_modules/.bin:$PATH"

Если вы положите это в свой ~/.profile, coffee всегда будет ./node_modules/.bin/coffee если доступно, в противном случае /usr/local/bin/coffee (или с любым другим префиксом, под которым вы устанавливаете модули узла).

Решение пути имеет проблему, что если $ (NPM Bin) помещается в ваш .profile / .bashrc / etc, он оценивается один раз и навсегда установлен на любой каталог, который был впервые оценен путь. Если вместо этого вы изменяетеТекущий путь Затем каждый раз, когда вы запускаете скрипт, ваш путь будет расти.

Чтобы обойти эти проблемы, я создаю функцию и использовал это.Это не изменяет вашу среду и просто использовать:

function npm-exec {
   $(npm bin)/$@  
}
.

Затем можно использовать так, как это без изменений в вашей среде:

npm-exec r.js <args>
.

Если вы хотите сохранить npm, то npx должен делать то, что вам нужно.


Если для вас возможен переход на пряжу (замена npm на Facebook), вы можете позвонить:

 yarn yourCmd

сценарии внутри package.json будут иметь приоритет; если ни один из них не найден, он будет искать внутри ./node_modules/.bin/ папка.

Он также выводит то, что он выполнил:

$ yarn tsc
yarn tsc v0.27.5
$ "/home/philipp/rate-pipeline/node_modules/.bin/tsc"

Таким образом, вам не нужно настраивать сценарии для каждой команды в вашем package.json.


Если у вас был сценарий, определенный в .scripts внутри твоего package.json:

"tsc": "tsc" // each command defined in the scripts will be executed from `./node_modules/.bin/` first

yarn tsc было бы эквивалентно yarn run tsc или npm run tsc:

 yarn tsc
 yarn tsc v0.27.5
 $ tsc

Обновление: если вы находитесь в последнем NPM (версия> 5.2)

Вы можете использовать:

npx <command>
.

npx ищет команду в каталоге .bin, если ваш node_modules

Старый ответ:

Для Windows

Храните следующее в файле, называемом npm-exec.bat и добавьте его к вашему генеракодичениюCode

@echo off
set cmd="npm bin"
FOR /F "tokens=*" %%i IN (' %cmd% ') DO SET modules=%%i
"%modules%"\%*
.

Использование

Тогда вы можете использовать это, как %PATH%

<Сильные> например,

Для выполнения npm-exec <command> <arg0> <arg1> ... установлен в локальном каталоге node_module, сделать:

npm-exec wdio wdio.conf.js
.

I.e.Он запускает wdio

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've always used the same approach as @guneysus to solve this problem, which is creating a script in the package.json file and use it running npm run script-name.

However, in the recent months I've been using npx and I love it.

For example, I downloaded an Angular project and I didn't want to install the Angular CLI globally. So, with npx installed, instead of using the global angular cli command (if I had installed it) like this:

ng serve

I can do this from the console:

npx ng serve

Here's an article I wrote about NPX and that goes deeper into it.

zxc is like "bundle exec" for nodejs. It is similar to using PATH=$(npm bin):$PATH:

$ npm install -g zxc
$ npm install gulp
$ zxc which gulp
/home/nathan/code/project1/node_modules/.bin/gulp

Same @regular 's accepted solution, but Fish shell flavour

if not contains (npm bin) $PATH
    set PATH (npm bin) $PATH
end

You can also use direnv and change the $PATH variable only in your working folder.

$ cat .envrc
> export PATH=$(npm bin):$PATH

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.

For Windows use this:

/* cmd into "node_modules" folder */
"%CD%\.bin\grunt" --version

I encountered the same problem and I don't particularly like using aliases (as regular's suggested), and if you don't like them too then here's another workaround that I use, you first have to create a tiny executable bash script, say setenv.sh:

#!/bin/sh

# Add your local node_modules bin to the path
export PATH="$(npm bin):$PATH"

# execute the rest of the command
exec "$@"

and then you can then use any executables in your local /bin using this command:

./setenv.sh <command>
./setenv.sh 6to5-node server.js
./setenv.sh grunt

If you're using scripts in package.json then:

...,
scripts: {
    'start': './setenv.sh <command>'
}

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"

I am a Windows user and this is what worked for me:

// First set some variable - i.e. replace is with "xo"
D:\project\root> set xo="./node_modules/.bin/"

// Next, work with it
D:\project\root> %xo%/bower install

Good Luck.

In case you are using fish shell and do not want to add to $path for security reason. We can add the below function to run local node executables.

### run executables in node_module/.bin directory
function n 
  set -l npmbin (npm bin)   
  set -l argvCount (count $argv)
  switch $argvCount
    case 0
      echo please specify the local node executable as 1st argument
    case 1
      # for one argument, we can eval directly 
      eval $npmbin/$argv
    case '*'
      set --local executable $argv[1]
      # for 2 or more arguments we cannot append directly after the $npmbin/ since the fish will apply each array element after the the start string: $npmbin/arg1 $npmbin/arg2... 
      # This is just how fish interoperate array. 
      set --erase argv[1]
      eval $npmbin/$executable $argv 
  end
end

Now you can run thing like:

n coffee

or more arguments like:

n browser-sync --version

Note, if you are bash user, then @Bob9630 answers is the way to go by leveraging bash's $@, which is not available in fishshell.

Include coffee-script in package.json with the specific version required in each project, typically like this:

"dependencies":{
  "coffee-script": ">= 1.2.0"

Then run npm install to install dependencies in each project. This will install the specified version of coffee-script which will be accessible locally to each project.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top