Установите зависимости глобально и локально, используя package.json

189

Используя npm, мы можем установить модули глобально, используя -gопцию. Как мы можем сделать это в файле package.json?

Предположим, это мои зависимости в файле package.json

"dependencies": {
    "mongoose": "1.4.0",
    "node.io" : "0.3.3",
    "jquery"  : "1.5.1",
    "jsdom"   : "0.2.0",
    "cron"    : "0.1.2"
  }

Когда я бегу npm install, я хочу node.ioустановить только глобально, остальные должны быть установлены локально. Есть ли вариант для этого?

Madhusudhan
источник
11
Ты не можешь Однако вы можете установить "preferGlobal": trueвнутри package.json для модуля.
Райнос
да, я знаю о <code> предпочитаемом глобальном </ code>, но это установит все зависимости глобально ... в любом случае, спасибо! Я думаю, что нет такой функции ...
Madhusudhan
3
Я не думаю, что это так. Он устанавливает текущий модуль глобально. Если для индивидуальной зависимости установлено значение true, она также может быть установлена ​​глобально. На самом деле вы должны просто спросить @isaacs в # node.js
Raynos
3
Глобальные установки могут создать ад зависимости. Скажем, пакет A требует версию 0.3.3 и пакет B версию 0.3.4, и оба не работают с другой версией. Тогда вам понадобятся две машины для размещения двух пакетов.
nalply
6
Ни один из этих комментариев не поможет мне в этом вопросе ... было бы неплохо, если бы код показал мне больше, чем просто "preferGlobal":true... я действительно не знаю, где поместить это в package.json. npmjs.org/doc/json.html Документация NPM гласит, что предпочитаетGlobal для вашего собственного пакета, и что его установка заставит его установить ваш глобальный пакет. похоже, больше похоже на руководство.
PPPaul

Ответы:

216

Новое примечание: вы, вероятно, не хотите или должны делать это. Что вы, вероятно, хотите сделать, это просто поместить эти типы командных зависимостей для сборки / тестирования и т. Д. В devDependenciesраздел вашего package.json. Каждый раз, когда вы что-то используете из scriptspackage.json, ваши команды devDependencies (в node_modules / .bin) действуют так, как будто они находятся на вашем пути.

Например:

npm i --save-dev mocha # Install test runner locally
npm i --save-dev babel # Install current babel locally

Тогда в package.json:

// devDependencies has mocha and babel now

"scripts": {
  "test": "mocha",
  "build": "babel -d lib src",
  "prepublish": "babel -d lib src"
}

Затем в командной строке вы можете запустить:

npm run build # finds babel
npm test # finds mocha

npm publish # will run babel first

Но если вы действительно хотите установить глобально, вы можете добавить предустановку в разделе сценариев package.json:

"scripts": {
  "preinstall": "npm i -g themodule"
}

Так что на самом деле моя установка npm снова выполняет установку npm, что странно, но, похоже, работает.

Примечание: у вас могут возникнуть проблемы, если вы используете наиболее распространенную установку, для npmкоторой требуется глобальная установка пакета Node sudo. Один из вариантов - изменить npmконфигурацию, так что в этом нет необходимости:

npm config set prefix ~/npmдобавьте $ HOME / npm / bin в $ PATH, добавив export PATH=$HOME/npm/bin:$PATHк вашему ~/.bashrc.

Джейсон Ливисей
источник
3
Я не смог заставить это работать npm i -g underscore-cli. это дает предупреждение о неправильности wd. WD означает рабочий каталог, я думаю. когда я вручную делаю это в командной строке, тогда все идет хорошо, однако я бы предпочел, чтобы пользователь мог справиться с установкой моего кода с помощью простогоnpm install
PPPaul
3
PPPaul - у меня была та же проблема, когда я недавно попробовал этот трюк. Возможно, мои настройки сейчас другие или он работает только с определенными модулями. В противном случае, я думаю, что-то изменилось с npm?
Джейсон Ливисей
9
В дополнение к этому вы можете предварительно проверить, установлен ли пакет: npm list module -g || npm install module -gnpm вернет правильные значения выхода.
m90
3
@CMCDragonkai: Это действительно должен быть отдельный вопрос. Но вы помещаете свои команды в сценарий и указываете сценарий как команду для выполнения (например "preinstall" : "scripts/preinstall.sh").
Мы все Моника
1
@CMCDragonkai &&, например, npm install -g bower && npm install -g grunt-cli
согласен
12

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

Используйте, npm install --save-dev [package_name]затем выполните сценарии с:

$ npm run lint
$ npm run build
$ npm test

Мой оригинальный, но не рекомендуемый ответ следует.


Вместо использования глобальной установки вы можете добавить пакет в your devDependencies( --save-dev), а затем запустить бинарный файл из любой точки вашего проекта:

"$(npm bin)/<executable_name>" <arguments>...

В твоем случае:

"$(npm bin)"/node.io --help

Этот инженер предоставил npm-execпсевдоним в качестве ярлыка. Этот инженер использует сценарий под названием env.sh. Но я предпочитаю использовать $(npm bin)напрямую, чтобы избежать каких-либо дополнительных файлов или настроек.

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

  • потенциальные конфликты зависимостей с глобальными пакетами (@nalply)
  • нужда в sudo
  • необходимость установки префикса npm (хотя я все равно рекомендую его использовать)

Недостатки:

  • $(npm bin) не будет работать на Windows.
  • Инструменты глубже в вашем дереве разработки не появятся в npm binпапке. (Установите npm-run или npm-which, чтобы найти их.)

Кажется , лучшим решением является размещение общих задач (таких , как строительство и Минимизация) в разделе «сценарии» из ваших package.json, как показывает выше Джейсон.

joeytwiddle
источник
Добавить псевдоним в вашем .bashrcлегко добавить bin/каталог в PATHпеременную окружения: alias nodebin='export PATH=$(npm bin)/:$PATH'. Выполните, nodebinа затем вы можете просто ввести свои команды, как обычно.
Гитаарик
Я не знаю, почему это не сработает для команд. Конечно, вам нужно настроить его, и если вы не хотите использовать псевдоним, это ваш выбор. Но это не помешает использовать его в команде.
gitaarik
9

Это немного устарело, но я столкнулся с требованием, поэтому вот решение, которое я нашел.

Эта проблема:

Наша команда разработчиков поддерживает множество продуктов для веб-приложений .NET, которые мы переносим на AngularJS / Bootstrap. VS2010 нелегко поддается пользовательским процессам сборки, и мои разработчики постоянно работают над несколькими выпусками наших продуктов. Наша VCS - это Subversion (я знаю, я знаю. Я пытаюсь перейти на Git, но мой надоедливый маркетинговый персонал так требователен), и одно решение VS будет включать несколько отдельных проектов. Мне нужно, чтобы у моего персонала был общий метод инициализации среды разработки без необходимости устанавливать одни и те же пакеты Node (gulp, bower и т. Д.) Несколько раз на одной машине.

TL; DR:

  1. Требуется «установка npm» для установки глобальной среды разработки Node / Bower, а также всех локально необходимых пакетов для продукта .NET.

  2. Глобальные пакеты должны быть установлены, только если они еще не установлены.

  3. Локальные ссылки на глобальные пакеты должны создаваться автоматически.

Решение:

У нас уже есть общая среда разработки, общая для всех разработчиков и всех продуктов, поэтому я создал скрипт NodeJS для установки глобальных пакетов при необходимости и создания локальных ссылок. Сценарий находится в ".... \ SharedFiles" относительно базовой папки продукта:

/*******************************************************************************
* $Id: npm-setup.js 12785 2016-01-29 16:34:49Z sthames $
* ==============================================================================
* Parameters: 'links' - Create links in local environment, optional.
* 
* <p>NodeJS script to install common development environment packages in global
* environment. <c>packages</c> object contains list of packages to install.</p>
* 
* <p>Including 'links' creates links in local environment to global packages.</p>
* 
* <p><b>npm ls -g --json</b> command is run to provide the current list of 
* global packages for comparison to required packages. Packages are installed 
* only if not installed. If the package is installed but is not the required 
* package version, the existing package is removed and the required package is 
* installed.</p>.
*
* <p>When provided as a "preinstall" script in a "package.json" file, the "npm
* install" command calls this to verify global dependencies are installed.</p>
*******************************************************************************/
var exec = require('child_process').exec;
var fs   = require('fs');
var path = require('path');

/*---------------------------------------------------------------*/
/* List of packages to install and 'from' value to pass to 'npm  */
/* install'. Value must match the 'from' field in 'npm ls -json' */
/* so this script will recognize a package is already installed. */
/*---------------------------------------------------------------*/
var packages = 
  {
  "bower"                      :                      "bower@1.7.2", 
  "event-stream"               :               "event-stream@3.3.2",
  "gulp"                       :                       "gulp@3.9.0",
  "gulp-angular-templatecache" : "gulp-angular-templatecache@1.8.0",
  "gulp-clean"                 :                 "gulp-clean@0.3.1", 
  "gulp-concat"                :                "gulp-concat@2.6.0",
  "gulp-debug"                 :                 "gulp-debug@2.1.2",
  "gulp-filter"                :                "gulp-filter@3.0.1",
  "gulp-grep-contents"         :         "gulp-grep-contents@0.0.1",
  "gulp-if"                    :                    "gulp-if@2.0.0", 
  "gulp-inject"                :                "gulp-inject@3.0.0", 
  "gulp-minify-css"            :            "gulp-minify-css@1.2.3",
  "gulp-minify-html"           :           "gulp-minify-html@1.0.5",
  "gulp-minify-inline"         :         "gulp-minify-inline@0.1.1",
  "gulp-ng-annotate"           :           "gulp-ng-annotate@1.1.0",
  "gulp-processhtml"           :           "gulp-processhtml@1.1.0",
  "gulp-rev"                   :                   "gulp-rev@6.0.1",
  "gulp-rev-replace"           :           "gulp-rev-replace@0.4.3",
  "gulp-uglify"                :                "gulp-uglify@1.5.1",
  "gulp-useref"                :                "gulp-useref@3.0.4",
  "gulp-util"                  :                  "gulp-util@3.0.7",
  "lazypipe"                   :                   "lazypipe@1.0.1",
  "q"                          :                          "q@1.4.1",
  "through2"                   :                   "through2@2.0.0",

  /*---------------------------------------------------------------*/
  /* fork of 0.2.14 allows passing parameters to main-bower-files. */
  /*---------------------------------------------------------------*/
  "bower-main"                 : "git+https://github.com/Pyo25/bower-main.git" 
  }

/*******************************************************************************
* run */
/**
* Executes <c>cmd</c> in the shell and calls <c>cb</c> on success. Error aborts.
* 
* Note: Error code -4082 is EBUSY error which is sometimes thrown by npm for 
* reasons unknown. Possibly this is due to antivirus program scanning the file 
* but it sometimes happens in cases where an antivirus program does not explain 
* it. The error generally will not happen a second time so this method will call 
* itself to try the command again if the EBUSY error occurs.
* 
* @param  cmd  Command to execute.
* @param  cb   Method to call on success. Text returned from stdout is input.
*******************************************************************************/
var run = function(cmd, cb)
  {
  /*---------------------------------------------*/
  /* Increase the maxBuffer to 10MB for commands */
  /* with a lot of output. This is not necessary */
  /* with spawn but it has other issues.         */
  /*---------------------------------------------*/
  exec(cmd, { maxBuffer: 1000*1024 }, function(err, stdout)
    {
    if      (!err)                   cb(stdout);
    else if (err.code | 0 == -4082) run(cmd, cb);
    else throw err;
    });
  };

/*******************************************************************************
* runCommand */
/**
* Logs the command and calls <c>run</c>.
*******************************************************************************/
var runCommand = function(cmd, cb)
  {
  console.log(cmd);
  run(cmd, cb);
  }

/*******************************************************************************
* Main line
*******************************************************************************/
var doLinks  = (process.argv[2] || "").toLowerCase() == 'links';
var names    = Object.keys(packages);
var name;
var installed;
var links;

/*------------------------------------------*/
/* Get the list of installed packages for   */
/* version comparison and install packages. */
/*------------------------------------------*/
console.log('Configuring global Node environment...')
run('npm ls -g --json', function(stdout)
  {
  installed = JSON.parse(stdout).dependencies || {};
  doWhile();
  });

/*--------------------------------------------*/
/* Start of asynchronous package installation */
/* loop. Do until all packages installed.     */
/*--------------------------------------------*/
var doWhile = function()
  {
  if (name = names.shift())
    doWhile0();
  }

var doWhile0 = function()
  {
  /*----------------------------------------------*/
  /* Installed package specification comes from   */
  /* 'from' field of installed packages. Required */
  /* specification comes from the packages list.  */
  /*----------------------------------------------*/
  var current  = (installed[name] || {}).from;
  var required =   packages[name];

  /*---------------------------------------*/
  /* Install the package if not installed. */
  /*---------------------------------------*/
  if (!current)
    runCommand('npm install -g '+required, doWhile1);

  /*------------------------------------*/
  /* If the installed version does not  */
  /* match, uninstall and then install. */
  /*------------------------------------*/
  else if (current != required)
    {
    delete installed[name];
    runCommand('npm remove -g '+name, function() 
      {
      runCommand('npm remove '+name, doWhile0);
      });
    }

  /*------------------------------------*/
  /* Skip package if already installed. */
  /*------------------------------------*/
  else
    doWhile1();
  };

var doWhile1 = function()
  {
  /*-------------------------------------------------------*/
  /* Create link to global package from local environment. */
  /*-------------------------------------------------------*/
  if (doLinks && !fs.existsSync(path.join('node_modules', name)))
    runCommand('npm link '+name, doWhile);
  else
    doWhile();
  };

Теперь, если я хочу обновить глобальный инструмент для наших разработчиков, я обновляю объект «пакеты» и регистрирую новый скрипт. Мои разработчики проверили его и либо запустили с "node npm-setup.js", либо с помощью "npm install" из любого разрабатываемого продукта для обновления глобальной среды. Все это занимает 5 минут.

Кроме того, чтобы настроить среду для нового разработчика, они должны сначала только установить NodeJS и GIT для Windows, перезагрузить компьютер, проверить папку «Общие файлы» и все разрабатываемые продукты и начать работать.

«Package.json» для продукта .NET вызывает этот сценарий перед установкой:

{ 
"name"                    : "Books",
"description"             : "Node (npm) configuration for Books Database Web Application Tools",
"version"                 : "2.1.1",
"private"                 : true,
"scripts":
  {
  "preinstall"            : "node ../../SharedFiles/npm-setup.js links",
  "postinstall"           : "bower install"
  },
"dependencies": {}
}

Ноты

  • Обратите внимание, что ссылка на скрипт требует косой черты даже в среде Windows.

  • «npm ls» выдаст «npm ERR! extraneous:» сообщения для всех локально связанных пакетов, так как они не перечислены в «package.json» «зависимости».

Редактировать 29.01.16

Обновленный npm-setup.jsскрипт выше был изменен следующим образом:

  • Пакет «версия» в var packagesтеперь является значением «пакета», передаваемым npm installв командной строке. Это было изменено, чтобы разрешить установку пакетов не из зарегистрированного репозитория.

  • Если пакет уже установлен, но не запрошен, существующий пакет будет удален, а правильный установлен.

  • По неизвестным причинам npm будет периодически выдавать ошибку EBUSY (-4082) при установке или ссылке. Эта ошибка перехвачена и команда повторно выполнена. Ошибка редко случается во второй раз и, кажется, всегда устраняется.

sthames42
источник
Это спасатель @ sthames42! Я часами троллю, пытаясь понять, как именно это сделать. Понятно, комплексно, в целом офигенно. #points Вопросы: (а) Почему Bower находится в postinstall, когда он уже находится в списке пакетов? (б) Как НЕ локально связать глобальные пакеты? Просто не включайте «ссылки» в команду?
MaxRocket
@MaxRocket: Рад, что смог помочь. Я обновил ответ, чтобы включить мой последний, который работает намного лучше. Ответы: (a) команда «bower install» запускается после «npm install» для установки компонентов Bower, перечисленных в файле bower.json, который здесь не показан. Я хотел, чтобы мои люди могли набирать 'npm install' и полностью настраивать свою среду без необходимости вводить другую команду. (б) Да.
sthames42
Текущая версия этого скрипта теперь поддерживается здесь .
sthames42
6

Вы можете использовать отдельный файл, например npm_globals.txt, вместо package.json. Этот файл будет содержать каждый модуль в новой строке, как это,

mongoose@1.4.0
node.io@0.3.3
jquery@1.5.1
jsdom@0.2.0
cron@0.1.2

Затем в командной строке запустите,

< npm_globals.txt xargs npm install -g

Проверьте, правильно ли они установлены,

npm list -g --depth=0

Что касается того, следует ли вам делать это или нет, я думаю, что все зависит от варианта использования. Для большинства проектов это не обязательно; и очень важно, чтобы ваш проект package.jsonинкапсулировал эти инструменты и зависимости вместе.

Но в настоящее время я обнаруживаю, что я всегда устанавливаю create-react-appи другие CLI глобально, когда я прыгаю на новую машину. Приятно иметь простой способ установки глобального инструмента и его зависимостей, когда управление версиями не имеет большого значения.

И в наши дни, я использую npx, НПМ пакет бегуна , вместо установки пакетов в глобальном масштабе.

Atav32
источник
3

Все модули из package.json установлены в ./node_modules/

Я не смог найти это явно указано, но это ссылка package.json для NPM .

nibblebot
источник
1

Создайте свой собственный скрипт для установки глобальных зависимостей. Это не займет много. package.json достаточно расширяемый.

const {execSync} = require('child_process');

JSON.parse(fs.readFileSync('package.json'))
     .globalDependencies.foreach(
         globaldep => execSync('npm i -g ' + globaldep)
     );

Используя вышеупомянутое, вы можете даже сделать это встроенным, ниже!

Посмотрите на preinstall ниже:

{
  "name": "Project Name",
  "version": "0.1.0",
  "description": "Project Description",
  "main": "app.js",
  "scripts": {
    "preinstall": "node -e \"const {execSync} = require('child_process'); JSON.parse(fs.readFileSync('package.json')).globalDependencies.foreach(globaldep => execSync('npm i -g ' + globaldep));\"",
    "build": "your transpile/compile script",
    "start": "node app.js",
    "test": "./node_modules/.bin/mocha --reporter spec",
    "patch-release": "npm version patch && npm publish && git add . && git commit -m \"auto-commit\" && git push --follow-tags"
  },
  "dependencies": [
  },
  "globalDependencies": [
    "cordova@8.1.2",
    "ionic",
    "potato"
  ],
  "author": "author",
  "license": "MIT",
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^5.2.0"
  },
  "bin": {
    "app": "app.js"
  }
}

Авторы узла могут не допустить package.json - это файл проекта. Но это.

TamusJRoyce
источник