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

使用npm,我们可以使用-g选项全局安装模块。我们如何在包装中做到这一点。json文件吗?

假设这些是我在包中的依赖项。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,其余的应该在本地安装。有其他选择吗?

134599 次浏览

所有模块从包。Json被安装到。/node_modules/

我找不到明确的说明,但这是包。NPM的json引用。

你可能不想或不需要这样做。你可能想要做的就是把这些类型的build/test等命令依赖放在package.json的devDependencies部分。当你在package中使用scripts中的东西时。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

新建新建:现在我们已经有了npx,它允许你运行devDependencies命令,而不需要将它们添加到你的scripts部分(如果你想的话)。 例如:< / p >

npx webpack

如果你想要全局安装,你可以在package.json的scripts部分添加一个preinstall:

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

所以实际上我的npm install再次执行npm install ..这很奇怪,但似乎很有效。

注意:如果你正在使用最常见的npm设置,其中全局Node包安装需要sudo,你可能会遇到问题。一个选项是改变你的npm配置,这样就没有必要了:

npm config set prefix ~/npm,通过将export PATH=$HOME/npm/bin:$PATH附加到你的~/.bashrc,将$HOME/npm/bin添加到$PATH。

另一个更好的选择是使用nvm来管理Node,这样就不会有这个问题了。

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

使用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

这个工程师提供了一个npm-exec别名作为快捷方式。这个工程师使用名为env.sh的shell脚本。但我更喜欢直接使用$(npm bin),以避免任何额外的文件或设置。

虽然它会使每次调用变大一点,但它应该< em > < / em >只是工作,防止:

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

缺点:

  • $(npm bin)将不能在Windows上工作。
  • 在你的开发树中更深的工具将不会出现在npm bin文件夹中。(安装npm-runnpm-which来找到它们。)

更好的解决方案似乎是把常见的任务(比如建造和缩小)放在你的package.json“脚本”部分中,就像Jason上面演示的那样。

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

存在的问题:

我们的开发团队维护了许多。net web应用产品,我们正在迁移到AngularJS/Bootstrap。VS2010不容易进行自定义构建过程,我的开发人员经常开发我们产品的多个版本。我们的vc是Subversion(我知道,我知道。我试图转移到Git,但我讨厌的营销人员要求很高),一个VS解决方案将包括几个独立的项目。我需要我的员工有一种通用的方法来初始化他们的开发环境,而不必在同一台机器上多次安装相同的Node包(gulp、bower等)。

TL;博士:

  1. 需要“npm install”来安装全局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();
};

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

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

“包。.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中,脚本引用也需要正斜杠 李环境。< / p > < / >

  • "npm ls"将给出"npm ERR!无关的:“所有包的消息 本地链接,因为它们不在“package.json”中列出 “依赖性”。< / p > < /李>

编辑1/29/16

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

  • var packages中的包"version"现在是在命令行上传递给npm install的" Package "值。这被更改为允许从注册存储库以外的地方安装包。

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

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

你可以使用一个单独的文件,比如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一个NPM包运行器,而不是全局安装包。

构建自己的脚本来安装全局依赖项。这并不需要太多。包中。Json是相当可扩展的。

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


const package = JSON.parse(fs.readFileSync('package.json'));


let keys = Object.keys(package.dependencies);
let values = Object.values(package.dependencies);




for (let index = 0; index < keys.length; index++) {
const key = keys[index];
let value = values[index].replace("~", "").replace("^", "");


console.log(`Installing: ${key}@${value} globally`,);
execSync('npm i -g ' + `${key}@${value}`);
}

使用上面的,你甚至可以使它内联,下面!

请看下面的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"
}
}

节点的作者可能不承认包。Json是一个项目文件。但事实确实如此。

这可能是生产中出现问题的原因。 如果项目依赖项安装在项目文件夹之外,如果其他人删除或替换你的包或更改文件夹权限,代码可能会中断

将所有东西都放在一个文件夹中更持久,使系统更可预测,维护任务也更容易。