Answers:
所有程序包管理器都有很多缺点。您只需要选择可以忍受的内容即可。
npm开始管理node.js模块(这就是node_modules
默认情况下会放入软件包的原因),但是当与Browserify或webpack结合使用时,它也适用于前端。
Bower是专门为前端创建的,并且考虑到这一点已进行了优化。
npm比bower大得多,包括通用JavaScript(例如country-data
用于国家/地区信息或sorts
用于在前端或后端使用的排序功能)的Bower得多。
Bower的包装数量要少得多。
凉亭包括样式等。
npm专注于JavaScript。样式为单独下载或类似的东西需要npm-sass
或sass-npm
。
最大的区别是npm确实嵌套了依赖项(但默认情况下是平坦的),而Bower需要平坦的依赖项树(这给用户带来了依赖项解决的负担)。
嵌套的依赖关系树意味着您的依赖关系可以具有自己的依赖关系,也可以具有自己的依此类推。这允许两个模块要求具有相同依赖性的不同版本,并且仍然可以工作。请注意,从npm v3开始,依赖项树默认情况下将是扁平的(节省空间),并且仅在需要的地方嵌套,例如,如果两个依赖项需要它们自己的Underscore版本。
一些项目同时使用这两种方法,即它们将Bower用于前端软件包,将npm用于开发人员工具,例如Yeoman,Grunt,Gulp,JSHint,CoffeeScript等。
此答案是Sindre Sorhus答案的补充。npm和Bower之间的主要区别在于它们对待递归依赖项的方式。请注意,它们可以在单个项目中一起使用。
关于npm常见问题解答:(从2015年9月6日开始,archive.org链接)
在不嵌套依赖关系的情况下,避免依赖关系冲突要困难得多。这是npm工作方式的基础,并且已被证明是一种非常成功的方法。
在Bower主页上:
Bower针对前端进行了优化。Bower使用平面依赖树,每个程序包仅需要一个版本,从而将页面负载降至最低。
简而言之,npm旨在稳定。Bower旨在最小化资源负载。如果绘制依赖关系结构,则会看到以下内容:
npm:
project root
[node_modules] // default directory for dependencies
-> dependency A
-> dependency B
[node_modules]
-> dependency A
-> dependency C
[node_modules]
-> dependency B
[node_modules]
-> dependency A
-> dependency D
如您所见,它以递归方式安装了一些依赖项。依赖项A具有三个已安装的实例!
凉亭:
project root
[bower_components] // default directory for dependencies
-> dependency A
-> dependency B // needs A
-> dependency C // needs B and D
-> dependency D
在这里,您会看到所有唯一依赖项都处于同一级别。
那么,为什么要麻烦使用npm?
也许依赖项B需要与依赖项C不同的版本。npm安装了该依赖项的两个版本,因此无论如何都可以工作,但是Bower会给您带来冲突,因为它不喜欢重复(因为在网页上加载相同的资源是效率低下且成本高昂,也会造成一些严重的错误)。您将必须手动选择要安装的版本。这可能会导致其中一个依赖项中断,但是无论如何,这都是您需要修复的问题。
因此,常见的用法是使用Bower表示要在网页上发布的软件包(例如,运行时,避免重复),而将npm用于其他内容,例如测试,构建,优化,检查等(例如开发时间),而不必担心重复)。
npm 3更新:
与Bower相比,npm 3的功能仍然有所不同。它将全局安装依赖性,但仅针对遇到的第一个版本。其他版本安装在树中(父模块,然后是node_modules)。
npm
和最小的资源负载bower
。
TL; DR:日常使用中最大的区别不是嵌套的依赖关系……而是模块和全局变量之间的区别。
我认为以前的海报涵盖了一些基本区别。(npm使用嵌套依赖关系确实对管理大型,复杂的应用程序非常有帮助,尽管我认为这不是最重要的区别。)
但是,令我惊讶的是,没有人明确解释Bower和npm之间最根本的区别之一。如果您阅读上面的答案,将会在npm的上下文中看到经常使用的“模块”一词。但是它被随意提及,好像可能只是语法上的不同。
但是,模块与全局(或模块与“脚本”)之间的区别可能是Bower与npm之间最重要的区别。将所有内容放入模块的npm方法要求您更改为浏览器编写Javascript的方式,几乎可以肯定,这样做会更好。
<script>
标签一样的全球资源从根本上说,Bower与加载普通的脚本文件有关。无论这些脚本文件包含什么,Bower都将加载它们。这基本上意味着鲍尔就像包括普通老式所有脚本<script>
的在<head>
你的HTML中。
因此,您使用了相同的基本方法,但是却获得了一些不错的自动化便利:
bower install
在本地快速快速地获得所需的内容。bower.json
链接也将为您下载。但除此之外,Bower不会改变我们编写javascript的方式。Bower加载的文件内部没有任何变化。特别是,这意味着Bower加载的脚本中提供的资源(通常但并非总是如此)仍将定义为全局变量,可以在浏览器执行上下文中的任何位置使用。
Node领域中的所有代码(以及因此所有通过npm加载的代码)都被构造为模块(具体来说,作为CommonJS模块格式的实现,或者现在作为ES6模块)。因此,如果您使用NPM处理浏览器端的依赖关系(通过Browserify或其他执行相同工作的东西),则将以与Node相同的方式来构造代码。
比我解决“为什么要使用模块?”问题的人要聪明,但这是一个总结:
window.variable
。仍然经常发生的一种事故是分配this.variable
,而不是意识到this
实际上是window
在当前环境中。)对我而言,将模块用于前端代码可归结为:在更狭窄的上下文中工作,更易于推理和测试,并且对所发生的事情具有更大的确定性。
仅需30秒钟即可学习如何使用CommonJS / Node模块语法。在给定的JS文件中(该文件将是一个模块),首先声明要使用的任何外部依赖项,如下所示:
var React = require('react');
在文件/模块内部,您可以执行通常的操作,并创建一些要向外部用户公开的对象或函数,也许可以调用它myModule
。
在文件末尾,您可以导出要与世界共享的所有内容,如下所示:
module.exports = myModule;
然后,要在浏览器中使用基于CommonJS的工作流,您将使用Browserify之类的工具来抓取所有这些单独的模块文件,在运行时封装它们的内容,然后根据需要将它们相互注入。
而且,由于ES6模块(您可能会使用Babel或类似的东西转换为ES5)已经获得了广泛的接受,并且可以在浏览器或Node 4.0中使用,因此我们也应该对它们进行全面介绍。
有关在此平台中使用模块的模式的更多信息。
编辑(2017年2月):如今,Facebook的Yarn是npm的非常重要的潜在替换/补充:建立在npm给您的基础上的快速,确定性,脱机软件包管理。值得一看的任何JS项目,特别是因为它很容易交换进/出。
编辑(2019年5月)“鲍尔终于被弃用。故事结束。” (h / t:@DanDascalescu,如下,内容简明。)
而且,虽然Yarn 仍处于活动状态,但是一旦采用了Yarn的一些关键功能,它的许多动力就会转移回npm。
鲍尔终于被弃用了。故事结局。
来自Spotify JavaScript开发人员Mattias Petter Johansson:
在几乎所有情况下,更适合在Bower上使用Browserify和npm。这是比Bower更好的前端应用程序打包解决方案。在Spotify,我们使用npm打包整个Web模块(html,css,js),并且效果很好。
Bower将自己称为网络包装经理。如果真是这样,那真是太棒了-一个使我作为前端开发人员的生活更美好的软件包管理器将很棒。问题在于Bower没有为此目的提供专门的工具。它没有提供我不知道npm不能提供的工具,尤其是没有任何工具对前端开发人员特别有用。对于前端开发人员而言,在npm上使用Bower根本没有任何好处。
我们应该停止使用凉亭并在npm左右合并。幸运的是,这是正在发生的事情:
使用browserify或webpack,将所有模块连接成较大的缩小文件变得非常容易,这对于性能(特别是对于移动设备)而言非常出色。Bower并非如此,Bower需要更多的劳动力才能获得相同的效果。
npm还使您能够同时使用多个版本的模块。如果您没有做太多的应用程序开发,这最初可能会给您带来不好的影响,但是一旦您经历了几轮Dependency地狱,您就会意识到,拥有一个模块的多个版本的能力实在是很糟糕。很棒的功能。请注意,npm包含一个非常方便的重复数据删除工具,如果确实需要,它会自动确保仅使用模块的两个版本-如果两个模块都可以使用一个模块的相同版本,则将使用。但是,如果他们做不到,那么您将非常方便。
Bower维护模块的单一版本,它仅尝试帮助您为您选择正确/最佳的模块。
NPM对于节点模块更好,因为存在模块系统并且您在本地工作。Bower对浏览器很有用,因为当前只有全局范围,并且您希望对使用的版本非常有选择性。
我的团队从Bower搬到了npm,原因是:
有关更多详细信息,请参见“为什么我的团队使用npm而不是bower”。
从http://ng-learn.org/2013/11/Bower-vs-npm/找到了有用的解释
一方面,创建了npm来安装在node.js环境中使用的模块,或者安装使用node.js构建的开发工具,例如Karma,lint,minifiers等。npm可以在项目中本地安装模块(默认情况下在node_modules中),也可以全局安装模块以供多个项目使用。在大型项目中,指定依赖项的方法是创建一个名为package.json的文件,其中包含依赖项列表。当您运行npm install时,npm会识别该列表,然后npm install会为您下载并安装它们。
另一方面,创建Bower来管理您的前端依赖项。像jQuery,AngularJS,下划线等之类的库。类似于npm,它有一个文件,您可以在其中指定一个名为bower.json的依赖项列表。在这种情况下,通过运行bower install来安装您的前端依赖项,默认情况下,它们将它们安装在一个名为bower_components的文件夹中。
如您所见,尽管它们执行相似的任务,但是它们针对的是一组非常不同的库。
npm dedupe
,这有点过时了。参见Mattias的答案。
对于使用node.js的许多人来说,bower的主要好处是可以管理根本不是JavaScript的依赖项。如果他们正在使用可编译为javascript的语言,则可以使用npm来管理其某些依赖项。但是,并非所有依赖项都将是node.js模块。其中一些可编译为javascript的代码可能具有怪异的特定于源语言的处理方式,使得在用户期望使用源代码时,将它们传递给javascript时是一个不明智的选择。
并非npm软件包中的所有内容都必须是面向用户的javascript,但对于npm库软件包,至少其中一些应该是。