题 Bower和npm有什么区别?


两者之间有什么根本区别 bower 和 npm?只想要简单明了的东西。我见过一些同事用过 bower 和 npm 在他们的项目中可以互换。


1612
2017-09-05 16:53


起源


相关答案 stackoverflow.com/a/21199026/1310070 - sachinjain024
可能重复 Javascript依赖管理:npm vs bower vs volo? - anotherdave
这个问题的答案似乎已经过时了。如果我们使用支持平板依赖的npm 3,有人可以告诉我们2016年该怎么做吗? npm3和bower有什么区别,现在最好的做法是什么? - amdev
最重要的是,@ amdev:bower现已弃用。 npm(或纱线,这只是一个微小的差异)是它的位置。我不知道有任何可行的替代方案。 - XML


答案:


所有包管理器都有许多缺点。你只需挑选你可以忍受的东西。

历史

NPM 开始管理node.js模块(这就是包进入的原因 node_modules 默认情况下),但结合使用时它也适用于前端 Browserify 或WebPack。

鲍尔 是专为前端而创建的,并在此基础上进行了优化。

回购的大小

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

鲍尔的包装数量要少得多。

处理款式等

凉亭包括款式等。

npm专注于JavaScript。样式可以单独下载,也可以通过类似的方式下载 npm-sass 要么 sass-npm

依赖性处理

最大的区别是npm执行嵌套依赖项(但默认情况下是平坦的),而Bower需要一个平面依赖树 (将依赖性解决的负担放在用户身上)

嵌套依赖树意味着您的依赖项可以拥有自己的依赖项,可以拥有自己的依赖项,依此类推。这允许两个模块需要相同描述的不同版本并且仍然有效。请注意,从npm v3开始,依赖关系树将默认为flat(节省空间),并且只在需要的地方嵌套,例如,如果两个依赖关系需要他们自己的Underscore版本。

有些项目同时使用Bower作为前端软件包,npm用于开发人员工具,如Yeoman,Grunt,Gulp,JSHint,CoffeeScript等。


资源


1828
2017-09-06 08:09



为什么嵌套的依赖树在前端不能做得那么好? - Lars Nyström
前端npm包也不是一个平面依赖树吗?我正面临着“为什么我们需要2个包管理器?”困境。 - Steven Vachon
“平依赖树”是什么意思?平树是什么 - 列表?那不是一棵树。 - mvmn
实际上,路径也是树。这只是一个特例。来自WikiPedia:“在数学中,更具体地说,在图论中,树是一个无向图,其中任何两个顶点都只通过一条路径连接。” - Jørgen Fogh
npm 3现在支持平面依赖树。 - vasa


这个答案是Sindre Sorhus答案的补充。 npm和Bower之间的主要区别在于它们处理递归依赖的方式。请注意,它们可以在一个项目中一起使用。

npm FAQ (archive.org链接自2015年9月6日)

没有嵌套就很难避免依赖冲突   依赖。这是npm工作方式的基础,并具有   事实证明这是一种非常成功的方法。

鲍尔 主页:

Bower针对前端进行了优化。 Bower使用扁平依赖   树,每个包只需要一个版本,减少页面加载   至少。

简而言之,npm旨在稳定。 Bower的目标是最小的资源负荷。如果你绘制出依赖结构,你会看到:

故宫:

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需要不同版本的依赖关系A而不是依赖关系C.npm安装这个依赖关系的两个版本,所以无论如何它都会工作,但是鲍尔会给你一个 冲突 因为它不喜欢重复(因为在网页上加载相同的资源是非常低效和昂贵的,也可能会产生一些严重的错误)。您必须手动选择要安装的版本。这可能会导致其中一个依赖项中断,但这是您需要修复的东西。

因此,您希望在网页上发布的包的常见用法是Bower(例如 运行,你避免重复),并使用npm进行其他的东西,如测试,建立,优化,检查等(例如, 开发时间,重复不太重要)。

npm 3更新:

与Bower相比,npm 3仍然有所不同。它将全局安装依赖项,但仅适用于它遇到的第一个版本。其他版本安装在树中(父模块,然后是node_modules)。

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

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


338
2017-11-24 13:10



现在,“软件开发完全取决于权衡取舍,这几乎是陈词滥调”。这是一个很好的例子。一个人必须选择 或 更高的稳定性 npm  要么 最小的资源负载 bower。 - jfmercer
@Shrek我暗示说你实际上可以同时使用两者。他们有不同的目的,正如我在最后一段中所述。这不是我眼中的权衡。 - Justus Romijn
啊,我看到我误解了你。或者我没有仔细阅读。谢谢你的澄清。 :-)这两个都可以在没有权衡的情况下使用。 - jfmercer
@AlexAngas我添加了npm3的更新。与Bower相比,它仍然存在一些重大差异。 npm可能总是支持多个版本的依赖项,而Bower则不支持。 - Justus Romijn
npm 3靠近凉亭;) - ni3


TL; DR:日常使用中最大的不同之处不是嵌套依赖...它是模块和全局变量之间的区别。

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

然而,我很惊讶没有人明确解释过Bower和npm之间最基本的区别之一。如果您阅读上面的答案,您会在npm的上下文中看到经常使用的“模块”一词。但随便提到它,好像它甚至只是一个语法差异。

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

凉亭方法:全球资源,像 <script> 标签

从根本上说,Bower就是要加载普通的脚本文件。无论这些脚本文件包含什么,Bower都会加载它们。这基本上意味着Bower就像包含所有脚本一样简单 <script><head> 你的HTML。

所以,你已经习惯了相同的基本方法,但是你获得了一些很好的自动化方便:

  • 您曾经需要在项目仓库中包含JS依赖项(在开发时),或者通过CDN获取它们。现在,您可以在回购中跳过额外的下载权重,有人可以快速完成 bower install并立即在当地拥有他们需要的东西。
  • 如果Bower依赖项然后在其中指定自己的依赖项 bower.json,那些也将为您下载。

但除此之外, 鲍尔并没有改变我们写javascript的方式。 Bower加载的文件里面的内容根本不需要改变。特别是,这意味着Bower加载的脚本中提供的资源(通常但不总是)仍然被定义为 全局变量,可从浏览器执行上下文中的任何位置获得。

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

Node land中的所有代码(以及因此通过npm加载的所有代码)都被构造为模块(具体来说,作为一个实现 CommonJS模块格式或者现在,作为ES6模块)。因此,如果您使用NPM来处理浏览器端依赖项(通过Browserify或执行相同工作的其他事项),您将以与Node相同的方式构建代码。

聪明的人比我解决'为什么模块?'的问题,但这是一个胶囊摘要:

  • 模块内部的任何内容都是有效的 命名空间中,这意味着它不再是一个全局变量,你不能在没有意图的情况下偶然引用它。
  • 模块内的任何内容都必须有意地注入特定的上下文(通常是另一个模块)才能使用它
  • 这意味着您可以在应用程序的各个部分中拥有相同外部依赖项的多个版本(例如,lodash),它们不会发生冲突/冲突。 (这种情况经常发生,因为您自己的代码想要使用一个版本的依赖项,但是您的一个外部依赖项指定了另一个冲突。或者您有两个外部依赖项,每个都需要不同的版本。)
  • 因为所有依赖项都是手动注入特定模块的,所以很容易对它们进行推理。你知道一个事实: “我在这方面需要考虑的唯一代码就是我故意选择在这里注入”
  • 因为即使是注入模块的内容也是如此 封装 在你赋予它的变量后面,所有代码都在有限的范围内执行,惊喜和碰撞变得非常不可能。很可能,你的某个依赖项中的某些内容会在没有意识到的情况下意外地重新定义全局变量,或者你会这样做。 (它 能够 发生了,但你通常不得不用自己的方式来做这件事 window.variable。仍然倾向于发生的一次事故就是分配 this.variable,没有意识到这一点 this 实际上是 window 在目前的情况下。)
  • 当您想要测试单个模块时,您可以非常容易地知道:究竟还有哪些(依赖项)影响模块内部运行的代码?并且,因为您明确地注入了所有内容,所以您可以轻松地模拟这些依赖项。

对我来说,前端代码模块的使用归结为:在更窄的环境中工作,更容易推理和测试,并且对正在发生的事情有更大的确定性。


学习如何使用CommonJS / Node模块语法只需要大约30秒。在给定的JS文件中,您将首先声明要使用的任何外部依赖项,如下所示:

var React = require('react');

在文件/模块中,你可以做任何你想做的事情,并创建一些你想要向外部用户公开的对象或函数,或许也可以调用它 myModule

在文件末尾,您可以导出要与世界共享的任何内容,如下所示:

module.exports = myModule;

然后,要在浏览器中使用基于CommonJS的工作流,您将使用Browserify之类的工具来获取所有这些单独的模块文件,在运行时封装它们的内容,并根据需要将它们互相注入。

并且,由于ES6模块(你可能会通过Babel或类似的方式转发到ES5)正在获得广泛的认可,并且在浏览器或Node 4.0中工作,我们应该提到一个 好的概述 那些也是。

有关使用模块的模式的更多信息 这个甲板


编辑(2017年2月):Facebook的  对于npm来说,这是一个非常重要的潜在替代/补充:快速,确定,离线的包管理,建立在npm为您提供的基础之上。值得一看任何JS项目,特别是因为它很容易交换进/出。


256
2017-07-26 03:12



很高兴这个答案在这里,其他流行的答案没有提到这个细节。 npm迫使你编写模块化代码。 - Juan Mendes


2017年10月更新

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

老回答

来自Spotify的JavaScript开发人员Mattias Petter Johansson

几乎在所有情况下,使用Browserify和npm over Bower更合适。对于前端应用而言,它只是比Bower更好的打包解决方案。在Spotify中,我们使用npm来打包整个Web模块(html,css,js),它运行良好。

Bower将自己打造为网络的包管理者。如果这是真的那将是非常棒的 - 一个包装经理让我的生活变得更好,因为前端开发人员会很棒。问题是Bower没有为此目的提供专门的工具。它没有提供我知道npm没有的工具,尤其是没有对前端开发人员特别有用的工具。 前端开发人员使用Bower超过npm没有任何好处。

我们应该停止使用凉亭并在npm周围进行整合。谢天谢地,就是这样 正在发生

Module counts - bower vs. npm

使用browserify或webpack,将所有模块连接成大型缩小文件变得非常容易,这对于性能来说非常棒,特别是对于移动设备。 Bower不是这样,需要更多的劳动才能获得同样的效果。

npm还使您能够同时使用多个版本的模块。如果你没有做太多的应用程序开发,这可能最初会让你感到害怕,但是一旦你经历了几次 依赖地狱 你会发现能够拥有一个模块的多个版本是一个非常好的功能。请注意,npm包含非常方便 重复数据删除工具 如果你真的那么自动确保你只使用两个版本的模块  到 - 如果两个模块都 能够 使用相同版本的一个模块,他们会。但如果他们 不能,你有一个非常方便的。

(注意 的WebPack 和 卷起 截至2016年8月被广泛认为比Browserify更好。)


117
2017-07-04 10:48



我认为webpack和npm更好.. - refactor
<sarcasm>请记住,即使'hello world'npm项目也需要300多个模块才能运行...... </ sarcasm>:O - Mariusz Jamro
我不同意“大缩小文件”对于性能而言非常棒,特别是对于移动设备而言。恰恰相反:受限制的带宽需要按需加载的小文件。 - Michael Franzl
不是很好的建议。大多数npm包只是nodejs后端。如果你没有在后端使用javascript,或者你没有模块系统,那么包的数量是无关紧要的,因为Bower会更好地满足你的需求 - Gerardo Grignoli
@GerardoGrignoli: 凉亭正在走出困境。 - Dan Dascalescu


Bower维护单个版本的模块,它只会帮助您为您选择正确/最佳的模块。

Javascript依赖管理:npm vs bower vs volo?

NPM对于节点模块更好,因为有一个模块系统,你在本地工作。 Bower适用于浏览器,因为目前只有全局范围,并且您希望对所使用的版本保持高度选择性。


43
2017-07-19 20:59



我觉得Sindre在谈到嵌套依赖时提到了这一点。 - Games Brainiac
@GamesBrainiac你是对的,只是想我用自己的话来说。 - Sagivf
@Sagivf这些是 不 你自己的话,除非你也是那些提供原始答案的人 这里 - dayuloli
@Sagivf复制没有错 **相关部分 其他人的答案,如果他们自己没有提供答案。它只是告诉我一点你说“只是想我用自己的话说。”信贷应该到达应收贷款的地方。 - dayuloli
我不知道为什么你们这么回答这个答案。在这个答案中确实有新的信息/观点。 - Calvin


我的团队离开Bower并迁移到npm因为:

  • 程序化使用很痛苦
  • Bower的界面不断变化
  • 一些功能,如网址速记,完全被打破
  • 在同一个项目中同时使用Bower和npm是很痛苦的
  • 保持bower.json版本字段与git标记同步是痛苦的
  • 源代码管理!=包管理
  • CommonJS支持并不简单

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


31
2018-02-16 21:04





从中找到这个有用的解释 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会识别该列表,然后为您下载并安装它们。

另一方面,创建了bower来管理您的前端依赖项。像jQuery,AngularJS,下划线等库。与npm类似,它有一个文件,您可以在其中指定一个名为bower.json的依赖项列表。在这种情况下,您的前端依赖项是通过运行bower install来安装的,默认情况下将其安装在名为bower_components的文件夹中。

如您所见,尽管他们执行类似的任务,但他们的目标是一组完全不同的库。


14
2017-10-03 00:08



随着。的到来 npm dedupe,这有点过时了。看到 马蒂亚斯的回答。 - Dan Dascalescu