Bower和npm有什么区别?


1763

bower和之间的根本区别是npm什么?只需要简单明了的东西。我已经看到一些同事在他们的项目中使用bowernpm互换使用。




7
这个问题的答案似乎已经过时了。如果我们使用支持平面依赖的npm 3,有人可以告诉我们在2016年该怎么做吗?wince npm3和bower有什么区别?目前的最佳做法是什么?
amdev '16

2
底线,@ amdev:现在不建议使用bower。npm(或Yarn,仅稍有差异)就是它所在的位置。我不知道任何可行的选择。
XML

Answers:


1914

所有程序包管理器都有很多缺点。您只需要选择可以忍受的内容即可。

历史

npm开始管理node.js模块(这就是node_modules默认情况下会放入软件包的原因),但是当与Browserifywebpack结合使用时,它也适用于前端。

Bower是专门为前端创建的,并且考虑到这一点已进行了优化。

回购规模

npm比bower大得多,包括通用JavaScript(例如country-data用于国家/地区信息或sorts用于在前端或后端使用的排序功能)的Bower得多。

Bower的包装数量要少得多。

样式等的处理

凉亭包括样式等。

npm专注于JavaScript。样式为单独下载或类似的东西需要npm-sasssass-npm

依赖处理

最大的区别是npm确实嵌套了依赖项(但默认情况下是平坦的),而Bower需要平坦的依赖项树(这给用户带来了依赖项解决的负担)

嵌套的依赖关系树意味着您的依赖关系可以具有自己的依赖关系,也可以具有自己的依此类推。这允许两个模块要求具有相同依赖性的不同版本,并且仍然可以工作。请注意,从npm v3开始,依赖项树默认情况下将是扁平的(节省空间),并且仅在需要的地方嵌套,例如,如果两个依赖项需要它们自己的Underscore版本。

一些项目同时使用这两种方法,即它们将Bower用于前端软件包,将npm用于开发人员工具,例如Yeoman,Grunt,Gulp,JSHint,CoffeeScript等。


资源资源


37
为什么嵌套的依赖树在前端不能做到这一点?
LarsNyström2014年

24
前端npm软件包也可能不是平面依赖树吗?我面临着“为什么我们需要2个软件包管理器?” 困境。
Steven Vachon 2014年

38
“平面依赖树”是什么意思?扁树是什么-清单?那不是一棵树。
mvmn 2014年

14
实际上,路径也是一棵树。这只是一个特例。摘自WikiPedia:“在数学中,更具体地说在图论中,一棵树是无向图,其中任何两个顶点都通过一条路径连接。”
约尔根·福格

42
npm 3现在支持平面依赖树。
vasa 2015年

361

此答案是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)。

  • [node_modules]
    • Dep A v1.0
    • 部门B v1.0
      • Dep A v1.0 (使用根版本)
    • Dep C v1.0
      • dep A v2.0(此版本与根版本不同,因此它将是嵌套安装)

有关更多信息,我建议阅读npm 3文档。


4
如今,“软件开发全都需要权衡”,这几乎成了陈词滥调。这是一个很好的例子。必须选择要么具有更大的稳定性npm 最小的资源负载bower
jfmercer

6
@Shrek我隐式地声明您实际上可以同时使用两者。正如我在最后一段所说,它们有不同的目的。在我看来这不是一个折衷。
Justus Romijn 2015年

啊,我知道我误会了你。或我没有足够仔细地阅读。感谢您的澄清。:-)两者都可以不折衷地使用,这是很好的。
jfmercer

4
@AlexAngas我已经为npm3添加了更新。与Bower相比,它仍有一些主要差异。npm可能总是支持多种版本的依赖关系,而Bower不支持。
Justus Romijn

npm 3越来越接近凉亭;)
ni3

269

TL; DR:日常使用中最大的区别不是嵌套的依赖关系……而是模块和全局变量之间的区别。

我认为以前的海报涵盖了一些基本区别。(npm使用嵌套依赖关系确实对管理大型,复杂的应用程序非常有帮助,尽管我认为这不是最重要的区别。)

但是,令我惊讶的是,没有人明确解释Bower和npm之间最根本的区别之一。如果您阅读上面的答案,将会在npm的上下文中看到经常使用的“模块”一词。但是它被随意提及,好像可能只是语法上的不同。

但是,模块与全局(或模块与“脚本”)之间的区别可能是Bower与npm之间最重要的区别。将所有内容放入模块的npm方法要求您更改为浏览器编写Javascript的方式,几乎可以肯定,这样做会更好。

鲍尔方法:像<script>标签一样的全球资源

从根本上说,Bower与加载普通的脚本文件有关。无论这些脚本文件包含什么,Bower都将加载它们。这基本上意味着鲍尔就像包括普通老式所有脚本<script>的在<head>你的HTML中。

因此,您使用了相同的基本方法,但是却获得了一些不错的自动化便利:

  • 您曾经需要在开发过程中在项目存储库中包含JS依赖项,或者通过CDN获得它们。现在,您可以跳过存储库中多余的下载内容,因此有人可以bower install在本地快速快速地获得所需的内容。
  • 如果Bower依赖项随后在中指定了自己的依赖项,那么这些bower.json链接也将为您下载。

但除此之外,Bower不会改变我们编写javascript的方式。Bower加载的文件内部没有任何变化。特别是,这意味着Bower加载的脚本中提供的资源(通常但并非总是如此)仍将定义为全局变量,可以在浏览器执行上下文中的任何位置使用。

npm方法:通用JS模块,显式依赖注入

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。


13
很高兴这个答案在这里,其他流行的答案都没有提到这个细节。npm强制您编写模块化代码。
Juan Mendes

很抱歉,来自一个对javascript parland中的所有模糊事件不太关心的人,但是碰巧它经营着一个利用小型Web应用程序的企业。最近,由于不得不将Bower与工具包结合使用,我们被迫尝试npm,从而开发了织补Web东西。我可以告诉你,最大的不同是等待时间,npm需要一段时间。请记住,这是在编译xkcd卡通动画,而那些玩剑的家伙大喊“编译”给老板。多数民众赞成在npm添加到凉亭。
Pedro Rodrigues

129

2017年10月更新

鲍尔终于被弃用了。故事结局。

较旧的答案

来自Spotify JavaScript开发人员Mattias Petter Johansson

在几乎所有情况下,更适合在Bower上使用Browserify和npm。这是比Bower更好的前端应用程序打包解决方案。在Spotify,我们使用npm打包整个Web模块(html,css,js),并且效果很好。

Bower将自己称为网络包装经理。如果真是这样,那真是太棒了-一个使我作为前端开发人员的生活更美好的软件包管理器将很棒。问题在于Bower没有为此目的提供专门的工具。它没有提供我不知道npm不能提供的工具,尤其是没有任何工具对前端开发人员特别有用。对于前端开发人员而言,在npm上使用Bower根本没有任何好处。

我们应该停止使用凉亭并在npm左右合并。幸运的是,这是正在发生的事情

模块计数-Bower vs.npm

使用browserify或webpack,将所有模块连接成较大的缩小文件变得非常容易,这对于性能(特别是对于移动设备)而言非常出色。Bower并非如此,Bower需要更多的劳动力才能获得相同的效果。

npm还使您能够同时使用多个版本的模块。如果您没有做太多的应用程序开发,这最初可能会给您带来不好的影响,但是一旦您经历了几轮Dependency地狱,您就会意识到,拥有一个模块的多个版本的能力实在是很糟糕。很棒的功能。请注意,npm包含一个非常方便的重复数据删除工具,如果确实需要,它会自动确保仅使用模块的两个版本-如果两个模块都可以使用一个模块的相同版本,则将使用。但是,如果他们做不到,那么您将非常方便。

(请注意,截至 2016年8月,Webpack汇总功能被认为比Browserify更好。)


7
<sarcasm>请记住,即使'hello world'npm项目也需要300多个模块才能运行... </
sarcasm

1
我不同意“大型压缩文件”“对性能,特别是对移动设备的性能很棒”。恰恰相反:受限带宽需要小的文件,可按需加载。
Michael Franzl

不是很好的建议。大多数npm软件包仅是nodejs后端。如果您没有在后端使用javascript或没有适当的模块系统,则软件包的数量无关紧要,因为Bower会更好地满足您的需求
Gerardo Grignoli

4
@ GerardoGrignoli:凉亭即将出炉
Dan Dascalescu

45

Bower维护模块的单一版本,它仅尝试帮助您为您选择正确/最佳的模块。

Javascript依赖管理:NPM vs Bower vs Volo?

NPM对于节点模块更好,因为存在模块系统并且您在本地工作。Bower对浏览器很有用,因为当前只有全局范围,并且您希望对使用的版本非常有选择性。


4
我觉得Sindre在谈到嵌套依赖时提到了这一点。
Games Brainiac 2014年

5
@GamesBrainiac您的正确,只是以为我会用我自己的话说。
2014年

1
@Sagivf这些不是您自己的话,除非您也是在这里
wheresrhyss

4
@Sagivf 如果其他人自己未在此处提供答案,则复制其他人的答案中与**相关的内容并没有错。你说“只是以为我会用我自己的话说”,这让我有些烦恼。信用应该去应得的地方。
dayuloli 2015年

2
我不知道你们为什么这么选择这个答案。对于我的回答,确实有新的信息/观点。
加尔文

33

我的团队从Bower搬到了npm,原因是:

  • 程序化使用很痛苦
  • Bower的界面不断变化
  • 某些功能(例如url速记)已完全损坏
  • 在同一项目中同时使用Bower和npm会很痛苦
  • 使bower.json版本字段与git标签保持同步是很痛苦的
  • 源代码控制!=包管理
  • CommonJS支持并不简单

有关更多详细信息,请参见“为什么我的团队使用npm而不是bower”


17

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的文件夹中。

如您所见,尽管它们执行相似的任务,但是它们针对的是一组非常不同的库。


1
随着的到来npm dedupe,这有点过时了。参见Mattias的答案
Dan Dascalescu 2015年

7

对于使用node.js的许多人来说,bower的主要好处是可以管理根本不是JavaScript的依赖项。如果他们正在使用可编译为javascript的语言,则可以使用npm来管理其某些依赖项。但是,并非所有依赖项都将是node.js模块。其中一些可编译为javascript的代码可能具有怪异的特定于源语言的处理方式,使得在用户期望使用源代码时,将它们传递给javascript时是一个不明智的选择。

并非npm软件包中的所有内容都必须是面向用户的javascript,但对于npm库软件包,至少其中一些应该是。


这篇npmjs博客文章指出:“您的软件包可以包含任何东西,无论是ES6,客户端JS还是HTML和CSS。这些东西自然都可以与JavaScript并存,因此将它们放到那里。”
Dan Dascalescu

1
可以包含应该包含之间是有区别的。当然,它们可以包含任何内容,但是通常,它们应该包括某种与commonJS的接口。毕竟,它是“节点包管理器”。关于这些的部分很自然地随Javascript一起出现,这一点很重要。有很多与javascript切线相关的东西并不自然地伴随它出现。
jessopher 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.