NodeJS требует глобального модуля / пакета

160

Я пытаюсь установить глобально, а затем использовать foreverи forever-monitorвот так:

npm install -g forever forever-monitor

Я вижу обычный вывод, а также операции, которые копируют файлы в глобальный путь, но затем, если я пытаюсь это сделать, require("forever");я получаю сообщение об ошибке, говорящее о том, что модуль не найден.

Я использую последнюю версию как узла, так и npm, и я уже знаю об изменениях, внесенных npm в глобальную или локальную установку, но я действительно не хочу устанавливать localy в каждом проекте, и я работаю на платформе, которая не не поддерживает, linkпоэтому npm linkпосле глобальной установки я не могу.

Мой вопрос: почему я не могу требовать глобально установленного пакета? Это особенность или ошибка? Или я что-то не так делаю?

PS: Просто чтобы сделать это кристально ясным: я не хочу устанавливать локально.

alexandernst
источник
Я просто оставляю это здесь github.com/yarnpkg/yarn/issues/2049 github.com/yarnpkg/yarn/issues/2049#issuecomment-337870443
Мареки
так что ~/.config/yarn/globalдля пряжи
localhostdotdev

Ответы:

216

В Node.js require не смотрит в папку, где установлены глобальные модули.

Вы можете исправить это, установив переменную окружения NODE_PATH. В Linux это будет:

export NODE_PATH=/usr/lib/node_modules

Примечание. Это зависит от того, где на самом деле установлены ваши глобальные модули.

Смотрите: Загрузка из глобальных папок .

Даниэль Узуну
источник
24
На моей машине с Ubuntu 13.10 глобальный путь для модулей отличается от того, что вы здесь показываете. Я должен был использовать export NODE_PATH=/usr/local/lib/node_modulesвместо этого.
Дрю Ноакс
11
Если вы работаете в Windows 7/8 и не переопределили установки по умолчанию для Node, вероятно, сработает установка NODE_PATHпеременной среды C:\Users\{USERNAME}\AppData\Roaming\npm\node_modules.
Уэс Джонсон
5
@WesJohnson Just %AppData%\npm\node_modulesбудет работать на Windows 10.
theblang
6
Если я установлю, NODE_PATHмогу ли я использовать глобальные и локальные модули одновременно?
Пауло Оливейра
6
В качестве альтернативы вместо статического пути, т.е. если вы используете NVM:NODE_PATH=$(npm root -g)
holmberd
98

После того, как вы установили пакет глобально, вы должны связать локальный проект с глобальным пакетом

npm install express -g
cd ~/mynodeproject/
npm link express  

Смотри здесь

user568109
источник
2
Я работаю на платформе, которая не поддерживает ссылку (как говорится в моем вопросе) blog.nodejs.org/2011/04/06/npm-1-0-link
alexandernst
1
какую платформу вы используете?
user568109
1
Я действительно не хочу связываться со ссылкой (и символическими ссылками вообще). Я просто хочу установить пакеты глобально и требовать их. Я знаю, что NPM был перепроектирован, чтобы избежать этого, но насколько трудно было бы достичь чего-то подобного?
alexandernst
13
Что если у меня нет проекта? Say ~/some-stand-alone-random-nodejs-test.js. Я не хочу превращать мою домашнюю папку в каталог проекта. Я не хочу создавать новые папки для каждого небольшого эксперимента.
AnnanFay
1
Отлично работал на Windows 8.1. Из командной строки узла cd в локальную папку node_modules моих проектов. npm link <module>Затем вы увидите ярлык (ссылку), созданный в папке node_module ваших проектов со ссылкой на модуль глобального узла.
dynamiclynk
26

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

var pg = require("/usr/local/lib/node_modules/pg");

Это не идеально, но, учитывая, что Unity3d пытается «скомпилировать» весь javascript, который включен в каталог проекта, я действительно не могу установить какие-либо пакеты.

Томас Ингам
источник
4
Unity3D не поддерживает JavaScript. Он поддерживает JS-подобный синтаксис для своего интерпретатора / компилятора Boo (Boo - это Python-подобный язык для .NET), который обманчиво позиционируется как «JavaScript» . Более точное название языка, поддерживаемого Unity, - UnityScript . Поскольку он даже не похож на один и тот же язык, почти ни один из JS, написанных для Интернета или для Node.js, не будет работать в Unity. Намного больше информации о различиях на официальной вики Unity: wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
Слипп Д. Томпсон
19

Я знаю , что это старый вопрос, но я столкнулся с этим , когда пытаюсь сделать некоторые проверки версий , используя semverв preinstallсценарии в package.json. Так как я знал, что не могу зависеть от каких-либо локальных установленных модулей, я использовал это для запроса semverиз глобальной node_modulesпапки (в npmзависимости от этого я знаю, что она есть):

function requireGlobal(packageName) {
  var childProcess = require('child_process');
  var path = require('path');
  var fs = require('fs');

  var globalNodeModules = childProcess.execSync('npm root -g').toString().trim();
  var packageDir = path.join(globalNodeModules, packageName);
  if (!fs.existsSync(packageDir))
    packageDir = path.join(globalNodeModules, 'npm/node_modules', packageName); //find package required by old npm

  if (!fs.existsSync(packageDir))
    throw new Error('Cannot find global module \'' + packageName + '\'');

  var packageMeta = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json')).toString());
  var main = path.join(packageDir, packageMeta.main);

  return require(main);
}

Мне нравится этот подход, потому что он не требует установки каких-либо специальных модулей для использования.

Я не использовал такое NODE_PATHрешение, как предлагали другие, поскольку хотел, чтобы это работало на чьей-либо машине, без необходимости дополнительной настройки / настройки перед запуском npm installмоего проекта.

Как это закодировано, гарантированно найти только модули верхнего уровня (установленные с использованием npm install -g ...) или модули, необходимые для npm(перечислены dependenciesздесь: https://github.com/npm/npm/blob/master/package.json ). Если вы используете более новую версию NPM, он может найти зависимости от других глобально установленных пакетов, поскольку теперь существует более плоская структура node_modulesпапок.

Надеюсь, это кому-нибудь пригодится.

Джо Скин
источник
19

Согласно документации , Node.js будет искать в следующих местах по умолчанию:

  1. Путь, указанный в NODE_PATHпеременной среды .

    Примечание: NODE_PATHпеременная окружения установлена ​​в список абсолютных путей, разделенных двоеточиями.

  2. Текущая node_modulesпапка. (местный)

  3. $HOME/.node_modules (Глобальный)

    Примечание: $HOMEэто домашний каталог пользователя.

  4. $HOME/.node_libraries (Глобальный)
  5. $PREFIX/lib/node (Глобальный)

    Примечание: $PREFIXв Node.js, настроенные node_prefix.

    Чтобы проверить текущее значение node_prefix, запустите:

    node -p process.config.variables.node_prefix

    Примечание. Префикс соответствует --prefixпараметру во время сборки и относится к process.execPath. Не путать со значением из npm config get prefixкоманды. источник

Если данный модуль не может быть найден, это означает, что он не присутствует ни в одном из указанных выше мест.

Расположение глобальной корневой папки, в которой установлены модули, можно распечатать: npm root -g(по умолчанию путь вычисляется во время выполнения, если он не переопределен в npmrcфайле ).

Решение

Вы можете попробовать следующие обходные пути:

  • Укажите местоположение вашего глобального модуля в NODE_PATHпеременной среды. Например

    echo 'require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node

    Чтобы проверить и распечатать значение NODE_PATH, выполните:

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • Для более постоянного решения, свяжите вашу $HOME/.node_modulesглобальную пользовательскую папку, чтобы указать на корневую папку, выполнив эту команду:

    ln -vs "$(npm root -g)" "$HOME"/.node_modules

    Затем повторно протестируйте его с помощью echo 'require("forever")' | nodeкоманды :.

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

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • Настройте глобальное назначение установки в npmфайле userconfig (см . :)npm help 5 npmrc или с помощью userconfigparam ( --prefix).

    Для отображения текущей конфигурации, выполните команду: npm config list.

    Для редактирования текущей конфигурации, выполните команду: npm config edit.

  • Укажите полный путь расположения узловых модулей при вызове require(). Например

    require("/path/to/sub/module")
  • Установите пакет в другое место, например

    npm install forever -g --prefix "$HOME"/.node_modules

    Тем не менее, установка будет прервана ~/.node_modules/lib/node_modules/, поэтому местоположение еще нужно добавить.

    Смотрите: локальный установочный пакет npm в произвольном месте

  • Создайте символическую ссылку в текущей папке из расположения глобального пакета. Например

    npm link forever
kenorb
источник
Это выглядит как 4. Текущая папка node_modules. (локальный) имеет приоритет над 3. $ PREFIX / lib / node (global)
Киралий Иштван,
Локальные папки node_modules всегда имеют приоритет над глобальными папками!
Кирали Иштван,
14

Вы можете использовать пакет requiregдля решения этой проблемы:

var forever = require('requireg')('forever')

сделает свое дело.

Кроме того, есть еще один модуль, global-npmхотя он специфичен только для глобального использования npm, вы можете посмотреть короткий код и посмотреть, как работает этот метод.

JP Richardson
источник
интересно, но метод NODE_PATH, вероятно, более канонический
Александр Миллс
Прелесть в NODE_PATHтом, что вам не нужно менять код. (мой вариант использования - оценка многих студенческих проектов, где я не хочу запускать npm installкаждый из них, а также не хочу, чтобы они предоставляли node_modulesкаталог).
17
Нет, это не сработает, потому что вы не можете требовать, requiregво-первых, в этом весь смысл.
thisismydesign
6

Для утилит CLI, которые зависят от больших модулей, например puppeteer, я люблю порождать a npm root -gи использовать его для запроса глобального модуля.

try {
  const root = require('child_process').execSync('npm root -g').toString().trim()
  var puppeteer = require(root + '/puppeteer')
} catch (err) {
  console.error(`Install puppeteer globally first with: npm install -g puppeteer`)
  process.exit(1)
}
Кристоф Маруа
источник
3

Вы можете поместить эту строку в свой .profileфайл:

export NODE_PATH = "$ (префикс префикса конфигурации npm) / lib / node_modules"

Это позволит nodeиспользовать глобальный путь.

Луис Пауло
источник
1
Нет. Это общий способ получить глобальный node_modules. Это старый ответ, но я помню, что получил его где-то в документации. Во всяком случае, на моем компьютере (в 2020 году) глобальный node_modulesкаталог npm есть usr/lib/node_modules. В любом случае, я верю, npm config get prefixпотому что он используется глобально npm всякий раз, когда установлен глобальный пакет, поэтому он должен быть правильным.
Луис Пауло
1
В любом случае (я не сказал этого в своем первоначальном ответе, потому что у меня не было большого опыта работы с Node.JS), использование глобально установленных пакетов в программе - это крайний случай использования, и его редко следует делать, потому что в проекте это создаст проблемы всякий раз, когда проект передается в VCS и клонируется в другой среде из-за того, что эта конкретная зависимость отсутствует в package.jsonфайле или в yarn.lock/ package-lock.json.
Луис Пауло
1
Ой! Теперь я понимаю. Я полагаю, что вы путаете NODE_PATH с PATH. PATH - это место, где оболочка будет искать исполняемые файлы. NODE_PATH - это место, где узел будет искать пакеты. Он начнет с просмотра текущей node_modulesпапки на предмет наличия папки, затем ее родительской, потом родительской, ... пока не найдет node_modulesпапку, содержащую этот модуль. Однако, если вы устанавливаете пакет глобально, он не будет находиться внутри какой-либо node_modulesпапки выше текущего каталога скрипта, поэтому вы используете NODE_PATH в качестве запасного варианта, когда узел будет искать пакеты.
Луис Пауло
1
ахахахах @ Луис Пауло, ты совершенно прав !! Мне жаль! Я постараюсь удалить некоторые из моих комментариев, чтобы избежать путаницы, отличной работы и благодарности
Райан Тейлор
@ Райан Тейлор Вы не должны удалять комментарии и вопросы, как только они будут решены, потому что у кого-то еще могут быть такие же. Теперь это выглядит так, будто у меня был монолог в комментариях! ахахахах
Луис Пауло