node.js 使用 package.json 全局和本地安装依赖项
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6480549/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Install dependencies globally and locally using package.json
提问by Madhusudhan
Using npm we can install the modules globally using -goption. How can we do this in the package.json file?
使用 npm,我们可以使用-g选项全局安装模块。我们如何在 package.json 文件中做到这一点?
Suppose, these are my dependencies in package.json file
假设,这些是我在 package.json 文件中的依赖项
"dependencies": {
"mongoose": "1.4.0",
"node.io" : "0.3.3",
"jquery" : "1.5.1",
"jsdom" : "0.2.0",
"cron" : "0.1.2"
}
When i run npm install, I want only node.ioto be installed globally, the rest others should be installed locally. Is there an option for this?
当我运行时npm install,我只想node.io全局安装,其余的应该在本地安装。有没有这个选项?
回答by Jason Livesay
New Note:You probably don't want or need to do this. What you probably want to do is just put those types of command dependencies for build/test etc. in the devDependenciessection of your package.json. Anytime you use something from scriptsin package.json your devDependencies commands (in node_modules/.bin) act as if they are in your path.
新注意事项:您可能不想或不需要这样做。您可能想要做的只是将构建/测试等的这些类型的命令依赖devDependencies项放在 package.json的部分中。 每当您使用scriptspackage.json 中的某些内容时,您的 devDependencies 命令(在 node_modules/.bin 中)就好像它们在您的路径中一样。
For example:
例如:
npm i --save-dev mocha # Install test runner locally
npm i --save-dev babel # Install current babel locally
Then in package.json:
然后在 package.json 中:
// devDependencies has mocha and babel now
"scripts": {
"test": "mocha",
"build": "babel -d lib src",
"prepublish": "babel -d lib src"
}
Then at your command prompt you can run:
然后在您的命令提示符下,您可以运行:
npm run build # finds babel
npm test # finds mocha
npm publish # will run babel first
Butif you reallywant to install globally, you can add a preinstall in the scripts section of the package.json:
但是如果你真的想全局安装,你可以在 package.json 的 scripts 部分添加一个预安装:
"scripts": {
"preinstall": "npm i -g themodule"
}
So actually my npm install executes npm install again .. which is weird but seems to work.
所以实际上我的 npm install 再次执行 npm install .. 这很奇怪,但似乎有效。
Note:you might have issues if you are using the most common setup for npmwhere global Node package installs required sudo. One option is to change your npmconfiguration so this isn't necessary:
注意:如果您使用最常见的设置来npm安装全局 Node 包,您可能会遇到问题sudo。一种选择是更改您的npm配置,因此这不是必需的:
npm config set prefix ~/npm, add $HOME/npm/bin to $PATH by appending export PATH=$HOME/npm/bin:$PATHto your ~/.bashrc.
npm config set prefix ~/npm,通过附加export PATH=$HOME/npm/bin:$PATH到您的~/.bashrc.
回答by joeytwiddle
Due to the disadvantages described below, I would recommendfollowing the accepted answer:
由于下面描述的缺点,我建议遵循公认的答案:
Use
npm install --save-dev [package_name]then execute scripts with:$ npm run lint $ npm run build $ npm test
使用
npm install --save-dev [package_name]然后执行脚本:$ npm run lint $ npm run build $ npm test
My original but not recommendedanswer follows.
我的原始但不推荐的答案如下。
Instead of using a global install, you could add the package to your devDependencies(--save-dev) and then run the binary from anywhere inside your project:
您可以将包添加到devDependencies( --save-dev) 中,然后从项目内的任何位置运行二进制文件,而不是使用全局安装:
"$(npm bin)/<executable_name>" <arguments>...
In your case:
在你的情况下:
"$(npm bin)"/node.io --help
This engineerprovided an npm-execalias as a shortcut. This engineeruses a shellscript called env.sh. But I prefer to use $(npm bin)directly, to avoid any extra file or setup.
这位工程师提供了一个npm-exec别名作为快捷方式。 这位工程师使用了一个名为env.sh. 但我更喜欢$(npm bin)直接使用,以避免任何额外的文件或设置。
Although it makes each call a little larger, it should just work, preventing:
尽管它使每次调用都变大了一点,但它应该可以正常工作,防止:
- potential dependency conflicts with global packages (@nalply)
- the need for
sudo - the need to set up an npm prefix (although I recommend using one anyway)
- 与全局包的潜在依赖冲突(@nalply)
- 需要
sudo - 需要设置一个 npm 前缀(尽管我还是建议使用一个)
Disadvantages:
缺点:
$(npm bin)won't work on Windows.- Tools deeper in your dev tree will not appear in the
npm binfolder. (Install npm-runor npm-whichto find them.)
It seems a better solutionis to place common tasks (such as building and minifying) in the "scripts" sectionof your package.json, as Jason demonstrates above.
这似乎更好的解决方案是将常见任务(如建筑物和涅槃)中“脚本”部分你的package.json,贾森上面演示。
回答by sthames42
This is a bit old but I ran into the requirement so here is the solution I came up with.
这有点旧,但我遇到了要求,所以这是我想出的解决方案。
The Problem:
问题:
Our development team maintains many .NET web application products we are migrating to AngularJS/Bootstrap. VS2010 does not lend itself easily to custom build processes and my developers are routinely working on multiple releases of our products. Our VCS is Subversion (I know, I know. I'm trying to move to Git but my pesky marketing staff is so demanding) and a single VS solution will include several separate projects. I needed my staff to have a common method for initializing their development environment without having to install the same Node packages (gulp, bower, etc.) several times on the same machine.
我们的开发团队维护着许多正在迁移到 AngularJS/Bootstrap 的 .NET Web 应用程序产品。VS2010 不适合自定义构建过程,我的开发人员经常处理我们产品的多个版本。我们的 VCS 是 Subversion(我知道,我知道。我正在尝试迁移到 Git,但我讨厌的营销人员要求很高)并且单个 VS 解决方案将包括几个单独的项目。我需要我的员工有一个通用的方法来初始化他们的开发环境,而不必在同一台机器上多次安装相同的 Node 包(gulp、bower 等)。
TL;DR:
特尔;博士:
Need "npm install" to install the global Node/Bower development environment as well as all locally required packages for a .NET product.
Global packages should be installed only if not already installed.
Local links to global packages must be created automatically.
需要“npm install”来安装全局 Node/Bower 开发环境以及 .NET 产品所需的所有本地包。
仅当尚未安装全局包时才应安装。
必须自动创建到全局包的本地链接。
The Solution:
解决方案:
We already have a common development framework shared by all developers and all products so I created a NodeJS script to install the global packages when needed and create the local links. The script resides in "....\SharedFiles" relative to the product base folder:
我们已经有一个所有开发人员和所有产品共享的通用开发框架,所以我创建了一个 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" : "[email protected]",
"event-stream" : "[email protected]",
"gulp" : "[email protected]",
"gulp-angular-templatecache" : "[email protected]",
"gulp-clean" : "[email protected]",
"gulp-concat" : "[email protected]",
"gulp-debug" : "[email protected]",
"gulp-filter" : "[email protected]",
"gulp-grep-contents" : "[email protected]",
"gulp-if" : "[email protected]",
"gulp-inject" : "[email protected]",
"gulp-minify-css" : "[email protected]",
"gulp-minify-html" : "[email protected]",
"gulp-minify-inline" : "[email protected]",
"gulp-ng-annotate" : "[email protected]",
"gulp-processhtml" : "[email protected]",
"gulp-rev" : "[email protected]",
"gulp-rev-replace" : "[email protected]",
"gulp-uglify" : "[email protected]",
"gulp-useref" : "[email protected]",
"gulp-util" : "[email protected]",
"lazypipe" : "[email protected]",
"q" : "[email protected]",
"through2" : "[email protected]",
/*---------------------------------------------------------------*/
/* 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();
};
Now if I want to update a global tool for our developers, I update the "packages" object and check in the new script. My developers check it out and either run it with "node npm-setup.js" or by "npm install" from any of the products under development to update the global environment. The whole thing takes 5 minutes.
现在,如果我想为我们的开发人员更新一个全局工具,我会更新“packages”对象并签入新脚本。我的开发人员检查它并使用“node npm-setup.js”或“npm install”从任何正在开发的产品中运行它以更新全局环境。整个过程需要5分钟。
In addition, to configure the environment for the a new developer, they must first only install NodeJS and GIT for Windows, reboot their computer, check out the "Shared Files" folder and any products under development, and start working.
此外,要为新开发人员配置环境,他们必须首先安装 NodeJS 和 GIT for Windows,重新启动计算机,查看“共享文件”文件夹和任何正在开发的产品,然后开始工作。
The "package.json" for the .NET product calls this script prior to install:
.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": {}
}
Notes
笔记
Note the script reference requires forward slashes even in a Windows environment.
"npm ls" will give "npm ERR! extraneous:" messages for all packages locally linked because they are not listed in the "package.json" "dependencies".
请注意,即使在 Windows 环境中,脚本引用也需要正斜杠。
“npm ls”将为本地链接的所有包提供“npm ERR!extraneous:”消息,因为它们未在“package.json”“dependencies”中列出。
Edit 1/29/16
编辑 1/29/16
The updated npm-setup.jsscript above has been modified as follows:
npm-setup.js上面更新后的脚本修改如下:
Package "version" in
var packagesis now the "package" value passed tonpm installon the command line. This was changed to allow for installing packages from somewhere other than the registered repository.If the package is already installed but is not the one requested, the existing package is removed and the correct one installed.
For reasons unknown, npm will periodically throw an EBUSY error (-4082) when performing an install or link. This error is trapped and the command re-executed. The error rarely happens a second time and seems to always clear up.
包“版本”
var packages现在是传递给npm install命令行的“包”值。这已更改为允许从注册存储库以外的其他地方安装软件包。如果该软件包已安装但不是请求的软件包,则删除现有软件包并安装正确的软件包。
由于未知原因,npm 在执行安装或链接时会定期抛出 EBUSY 错误 (-4082)。此错误被捕获并重新执行命令。该错误很少发生第二次,并且似乎总是会清除。
回答by Atav32
You could use a separate file, like npm_globals.txt, instead of package.json. This file would contain each module on a new line like this,
您可以使用单独的文件,例如npm_globals.txt, 而不是package.json. 该文件将包含这样的新行中的每个模块,
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
Then in the command line run,
然后在命令行运行,
< npm_globals.txt xargs npm install -g
Check that they installed properly with,
检查它们是否正确安装,
npm list -g --depth=0
As for whether you shoulddo this or not, I think it all depends on use case. For most projects, this isn't necessary; and having your project's package.jsonencapsulate these tools and dependencies together is much preferred.
至于你是否应该这样做,我认为这一切都取决于用例。对于大多数项目,这不是必需的;并且让您的项目package.json将这些工具和依赖项封装在一起是更可取的。
But nowadays I find that I'm always installing create-react-appand other CLI's globally when I jump on a new machine. It's nice to have an easy way to install a global tool and its dependencies when versioning doesn't matter much.
但是现在我发现create-react-app当我跳到新机器上时,我总是在全球范围内安装和其他 CLI。当版本控制无关紧要时,有一种简单的方法来安装全局工具及其依赖项是很好的。
And nowadays, I'm using npx, an npm package runner, instead of installing packages globally.
回答by nibblebot
回答by TamusJRoyce
Build your own script to install global dependencies. It doesn't take much. package.json is quite expandable.
构建您自己的脚本以安装全局依赖项。不需要太多。package.json 是非常可扩展的。
const {execSync} = require('child_process');
JSON.parse(fs.readFileSync('package.json'))
.globalDependencies.foreach(
globaldep => execSync('npm i -g ' + globaldep)
);
Using the above, you can even make it inline, below!
使用上面的,你甚至可以让它内联,下面!
Look at preinstall below:
看看下面的预安装:
{
"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": [
"[email protected]",
"ionic",
"potato"
],
"author": "author",
"license": "MIT",
"devDependencies": {
"chai": "^4.2.0",
"mocha": "^5.2.0"
},
"bin": {
"app": "app.js"
}
}
The authors of node may not admit package.json is a project file. But it is.
node 的作者可能不承认 package.json 是一个项目文件。但它是。

