使用package.json在全局和本地安装依赖关系
使用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
,其他人应该在本地安装。 有没有这个选项?
新注意:您可能不想要或不需要这样做。 你可能想要做的只是把这些types的命令依赖关系进行构build/testing等在你的package.json devDependencies
部分。 每当你使用package.json中的scripts
,你的devDependencies命令(在node_modules / .bin中)就好像它们在你的path中一样。
例如:
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安装..这是奇怪的,但似乎工作。
注意:如果使用全局节点包安装所需的sudo
npm
最常用的设置,则可能有问题。 一种select是改变你的npm
configuration,所以这不是必须的:
npm config set prefix ~/npm
,通过将export PATH=$HOME/npm/bin:$PATH
到你的~/.bashrc
,将$ HOME / npm / bin添加到$ PATH中。
由于下面介绍的缺点,我会build议遵循接受的答案:
使用
npm install --save-dev [package_name]
然后执行脚本:$ npm run lint $ npm run build $ npm test
我的原始但不推荐的答案如下。
您可以将软件包添加到devDependencies
( --save-dev
devDependencies
--save-dev
),然后从项目中的任何位置运行二进制文件,而不是使用全局安装。
"$(npm bin)/<executable_name>" <arguments>...
在你的情况下:
"$(npm bin)"/node.io --help
这位工程师提供了一个npm-exec
别名作为快捷方式。 这个工程师使用一个名为env.sh
的shell env.sh
。 但我更喜欢直接使用$(npm bin)
,以避免任何额外的文件或设置。
虽然它使每个呼叫稍微大一点,但它应该只是起作用 ,防止:
- 潜在的依赖与全局软件包冲突(@nalply)
- 需要
sudo
- 需要设置一个npm前缀(尽pipe我推荐使用一个前缀)
缺点:
-
$(npm bin)
在Windows上不起作用。 - 你的开发树中更深的工具不会出现在
npm bin
文件夹中。 (安装npm-run或npm-find它们。)
如Jason所示,似乎更好的解决scheme是将常见任务(如构build和缩小)放在package.json
的“脚本”部分 。
这是有点老,但我遇到了这个要求,所以这是我想出的解决scheme。
问题:
我们的开发团队维护许多.NET Web应用程序产品,我们正在迁移到AngularJS / Bootstrap。 VS2010不适合自定义构build过程,我的开发人员经常在多个版本的产品上工作。 我们的VCS是Subversion(我知道,我知道,我正在尝试转移到Git,但是我讨厌的营销人员是如此的苛刻),一个VS解决scheme将包括几个独立的项目。 我需要我的工作人员有一个通用的方法来初始化他们的开发环境,而不必在同一台机器上多次安装相同的Node包(gulp,bower等)。
TL; DR:
-
需要“npm install”来安装全局的Node / Bower开发环境以及.NET产品的所有本地需要的包。
-
全局软件包只有在尚未安装的情况下才能安装。
-
本地链接到全局包必须自动创build。
解决scheme:
我们已经有了一个由所有开发人员和所有产品共享的通用开发框架,因此我创build了一个NodeJS脚本来在需要时安装全局程序包并创build本地链接。 该脚本驻留在相对于产品基本文件夹的“…. \ 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分钟。
另外,要为新开发人员configuration环境,他们必须首先安装NodeJS和GIT for Windows,重新启动计算机,检查“共享文件”文件夹以及任何正在开发的产品,然后开始工作。
.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”“dependencies”中列出。
编辑1/29/16
上面更新的npm-setup.js
脚本已被修改如下:
-
软件包中的“版本”现在是在命令行中传递给
npm install
的“软件包”值。 这已更改为允许从注册存储库以外的地方安装软件包。 -
如果软件包已经安装,但不是所请求的软件包,则删除现有的软件包并安装正确的软件包。
-
由于未知的原因,在执行安装或链接时,npm会周期性地抛出一个EBUSY错误(-4082)。 这个错误被困住,命令被重新执行。 这个错误很less再次发生,似乎总是清除。
package.json中的所有模块都安装到./node_modules/
我找不到明确说明,但这是NPM的package.json参考。