使用package.json在全局和本地安装依赖项

时间:2011-06-25 21:10:35

标签: node.js npm

使用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,其他的应该在本地安装。这有选择吗?

6 个答案:

答案 0 :(得分:203)

新注意:您可能不希望或不需要这样做。您可能想要做的只是将这些类型的命令依赖项放在build.json的devDependencies部分中进行构建/测试等。 只要你在package.json中使用scripts中的内容,你的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 install ..这很奇怪,但似乎有效。

注意:如果您使用npm的最常见设置,则可能会遇到问题,其中需要安装全局节点包sudo。一种选择是更改npm配置,因此不需要这样做:

npm config set prefix ~/npm,将$ HOME / npm / bin添加到$ PATH,方法是将export PATH=$HOME/npm/bin:$PATH添加到~/.bashrc

答案 1 :(得分:12)

由于下面描述的缺点,我建议遵循接受的答案:

  

使用npm install --save-dev [package_name]然后执行脚本:

$ npm run lint
$ npm run build
$ npm test

我的原始但不推荐的答案如下。


您可以将软件包添加到devDependencies--save-dev),然后从项目内的任何位置运行二进制文件,而不是使用全局安装:

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

在你的情况下:

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

This engineer提供了npm-exec别名作为快捷方式。 This engineer使用名为env.sh的shellcript。但我更喜欢直接使用$(npm bin),以避免任何额外的文件或设置。

虽然它会使每次调用都变得更大,但它应 正常工作 ,从而阻止:

  • 与全局包的潜在依赖冲突(@nalply)
  • 需要sudo
  • 需要设置npm前缀(尽管我建议使用一个前缀)

缺点:

  • $(npm bin)无法在Windows上工作。
  • 您的开发树中较深的工具不会显示在npm bin文件夹中。 (安装npm-runnpm-which即可找到它们。)

似乎更好的解决方案是在package.json的{​​{3}}中放置常见任务(例如构建和缩小),正如Jason在上面演示的那样。

答案 2 :(得分:9)

这有点旧,但我遇到了要求,所以这里是我提出的解决方案。

问题:

我们的开发团队维护着许多我们正在迁移到AngularJS / Bootstrap的.NET Web应用程序产品。 VS2010不易于自定义构建过程,我的开发人员经常处理我们产品的多个版本。我们的VCS是Subversion(我知道,我知道。我正在尝试转向Git,但我讨厌的营销人员要求很高)并且单个VS解决方案将包括几个单独的项目。我需要我的员工有一个通用的方法来初始化他们的开发环境,而无需在同一台机器上多次安装相同的Node包(gulp,bower等)。

<强> TL; DR:

  1. 需要“npm install”来安装全局Node / Bower开发环境以及.NET产品的所有本地所需的软件包。

  2. 只有在尚未安装全局软件包时才应安装。

  3. 必须自动创建指向全局包的本地链接。

  4. 解决方案:

    我们已经拥有了所有开发人员和所有产品共享的通用开发框架,因此我创建了一个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();
      };
    

    现在,如果我想为开发人员更新全局工具,我会更新“packages”对象并检入新脚本。我的开发人员检查它并使用“node npm-setup.js”或“npm install”从正在开发的任何产品中运行它来更新全局环境。整件事需要5分钟。

    此外,要为新开发人员配置环境,他们必须首先只安装NodeJS和GIT for Windows,重新启动计算机,查看“共享文件”文件夹以及正在开发的所有产品,然后开始工作。 / p>

    .NET产品的“package.json”在安装之前调用此脚本:

    { 
    "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”中列出 “依赖性”。

    编辑2016年1月29日

    上面更新的npm-setup.js脚本已修改如下:

    • var packages中的软件包“version”现在是命令行中传递给npm install的“软件包”值。这已更改为允许从注册存储库以外的其他位置安装软件包。

    • 如果软件包已经安装但不是所请求的软件包,则会删除现有软件包并安装正确的软件包。

    • 由于未知原因,npm会在执行安装或链接时定期抛出EBUSY错误(-4082)。捕获此错误并重新执行命令。错误很少发生第二次,似乎总是清空。

答案 3 :(得分:4)

package.json中的所有模块都安装到./node_modules /

我找不到明确说明的内容,但这是NPM的package.json参考。

答案 4 :(得分:4)

您可以使用单独的文件,例如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。在版本控制并不重要时,有一种简单的方法可以安装全局工具及其依赖项。

现在,我使用npxan npm package runner,而不是全局安装软件包。

答案 5 :(得分:0)

构建您自己的脚本以安装全局依赖项。不需要很多。 package.json相当可扩展。

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

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

使用以上内容,您甚至可以在下面将其内联!

在下面查看预安装:

{
  "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"
  }
}

node的作者可能不承认package.json是一个项目文件。但这是