Bower和npm有什么区别?

bowernpm之间的根本区别是什么? 只想要简单明了的东西。 我见过一些同事在他们的项目中交替使用bowernpm

npm最常用于pipe理Node.js模块,但与Browserify和/或$ npm dedupe结合使用时,它也可用于前端。

鲍尔是专门为前端而创build的,并且考虑到了这一点。 最大的区别在于,npm嵌套了依赖树(大小很重),而Bower需要一个平坦的依赖树(将依赖关系parsing的负担放在用户身上)

嵌套的依赖关系树意味着您的依赖关系可以拥有自己的依赖关系,可以拥有自己的依赖关系,依此类推。 这在服务器上真的很棒,你不必太在意空间和延迟。 它可以让你不必关心依赖冲突,因为你所有的依赖使用例如他们自己的Underscore版本。 这显然不能很好地在前端工作。 想象一下,一个网站必须下载三个jQuery副本。

许多项目同时使用的原因是他们使用Bower作为前端软件包,使用npm作为开发者工具,如Yeoman,Grunt,Gulp,JSHint,CoffeeScript等。

所有软件包pipe理者都有很多缺点。 你只需要select你可以住的地方。


资源

  • 嵌套的依赖关系 – 深入了解为什么node_modules的工作方式

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

在npm FAQ :

如果没有嵌套依赖关系,避免依赖冲突要困难得多。 这是npm工作方式的基础,已被certificate是非常成功的方法。

在鲍尔主页上:

Bower针对前端进行了优化。 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 

正如你所看到的,它会recursion地安装一些依赖项。 依赖项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会给你一个冲突,因为它不喜欢重复(因为在网页上加载相同的资源非常低效和昂贵,也可能会导致一些严重的错误)。 您将不得不手动select要安装的版本。 这可能会导致其中一个依赖关系会中断,但这是您需要解决的问题。

所以,对于想要在网页上发布的软件包(例如运行时 ,避免重复),通常的用法是Bower,并且使用npm作为其他的东西,比如testing,构build,优化,检查等等(例如开发时间 ,重复不太重要)。

npm 3更新:

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

  • [node_modules]
    • dep A v1.0
    • dep B v1.0
      • dep A v1.0 (使用根版本)
    • dep C v1.0
      • dep一个v2.0(这个版本不同于根版本,所以它会是一个嵌套的安装)

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

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

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

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

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

Bower方法:全球资源,就像<script>标签

在根目录下,Bower是关于加载纯文本脚本文件的。 无论这些脚本文件包含什么,Bower都会加载它们。 这基本上意味着Bower就像将所有的脚本包含在HTML的<head>的普通的<script>中。

所以,你习惯了同样的基本方法,但你会得到一些很好的自动化的便利:

  • 您以前需要将JS依赖项包含在您的项目库(开发中)中,或者通过CDN获取它们。 现在,您可以跳过这个额外的下载重量,有人可以做一个快速bower install并立即在本地有他们需要的东西。
  • 如果一个Bower依赖项在它的bower.json指定了它自己的依赖项,那么这些依赖bower.json也会被下载。

但除此之外, 鲍尔不会改变我们如何写javascript 。 关于Bower加载的文件,什么都不需要改变。 特别是,这意味着由Bower加载的脚本中提供的资源将(通常但不总是)仍然被定义为全局variables ,可以从浏览器执行上下文中的任何地方获得。

npm方法:通用JS模块,显式dependency injection

Node中的所有代码(通过npm加载所有代码)都是作为模块(特别是作为CommonJS模块格式的实现 ,或者现在作为ES6模块)来构造的。 因此,如果您使用NPM来处理浏览器端的依赖关系(通过Browserify或其他执行相同工作的东西),那么您将按照与Node相同的方式来构造您的代码。

比我更聪明的人解决了“为什么模块?”的问题,但是这里有一个胶囊摘要:

  • 模块内部的任何内容都是有效的命名空间 ,这意味着它不再是一个全局variables,而且不会意外地引用它。
  • 模块中的任何内容都必须被有意地注入特定的上下文中(通常是另一个模块)以便使用它
  • 这意味着你可以在你的应用程序的不同部分有多个版本的相同的外部依赖(lodash,比方说),它们不会相互冲突。 (这经常令人吃惊,因为你自己的代码想要使用一个版本的依赖关系,但是你的一个外部依赖关系指定了另外一个冲突,或者你有两个外部依赖关系,每个依赖关系都需要一个不同的版本。
  • 因为所有的依赖关系都是手动注入到特定的模块中,所以很容易推理它们。 你知道一个事实: “在这个过程中我唯一需要考虑的代码是我有意select在这里注入的”
  • 因为即使注入模块的内容被封装在你指定的variables之后,并且所有的代码都在有限的范围内执行,意外和碰撞变得非常不可能。 如果没有意识到这一点,或者您会这样做,那么您的某个依赖关系的某些事情就会不小心重新定义一个全局variables。 ( 可能会发生,但是你通常不得不这样做,像window.variable这样的事情,一个仍然倾向于发生的事故是分配这个this.variable ,没有意识到this实际上是在当前的window上下文。)
  • 当你想testing一个单独的模块时,你可以很容易地知道:还有什么(依赖)影响模块内运行的代码? 而且,因为你明确地注入了一切,所以你可以很容易地嘲笑这些依赖关系。

对我而言,前端代码模块的使用归结为:工作在更狭窄的环境中,更容易推理和testing,并对发生的事情有更大的把握。


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

var React = require('react');

在文件/模块内部,你可以做任何你想做的事情,创build一些你想要暴露给外部用户的对象或者函数,把它myModule

在一个文件的末尾,你可以导出任何你想要与世界分享的内容,比如:

module.exports = myModule;

然后,为了在浏览器中使用基于CommonJS的工作stream程,您将使用像Browserify这样的工具来抓取所有这些单独的模块文件,在运行时封装它们的内容,并根据需要将它们注入彼此。

而且,由于ES6模块(您可能会用Babel或类似的方式将其转换为ES5)正在得到广泛的接受,并且在浏览器或Node4.0中都可以使用,所以我们也应该对这些模块做一个很好的概述 。

更多关于在这个套牌中使用模块的模式。


编辑(2017年2月):Facebook的纱线现在是npm非常重要的潜在替代/补充:快速,确定性,离线包pipe理,build立在npm给你的东西上。 这是值得一看的任何JS项目,特别是因为它是很容易交换进出。

2017年5月更新

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

较老的答案

来自Spotify的JavaScript开发者Mattias Petter Johansson :

在几乎所有情况下,使用Browserify和npm over Bower更合适。 对于前端应用来说,这只是比Bower更好的打包解决scheme。 在Spotify中,我们使用npm打包整个网页模块(html,css,js),效果很好。

Bower将自己定位为networking的包pipe理者。 如果这是真的,那真是太棒了 – 一个让我的生活变得更好,像前端开发人员的软件包pipe理员将会是非常棒的。 问题在于Bower没有为此目的提供专门的工具。 它提供了没有任何工具,我知道npm没有,特别是没有什么是特别有用的前端开发人员。 对于前端开发者来说,使用Bower而不是npm是没有好处的。

我们应该停止使用凉亭和巩固周围npm。 谢天谢地,这就是发生了什么事情 :

模块计数 - 凉亭与npm

借助browserify或webpack,将所有模块连接成大型文件变得非常容易,对于性能尤其如此,特别是对于移动设备。 与鲍尔不同,这将需要更多的劳动才能获得相同的效果。

npm还可以让您同时使用多个版本的模块。 如果你没有做太多的应用程序开发,这可能最初会把你当成一件坏事,但是一旦你经历了几次Dependency地狱,你会意识到拥有一个模块的多个版本的能力是相当不错的很棒的function。 请注意,npm包含一个非常方便的重复数据删除工具 ,可以自动确保只使用两个版本的模块,如果您真的必须这样做 – 如果两个模块都可以使用同一版本的一个模块,他们会。 但是,如果他们不能 ,你有一个非常方便。

(请注意, 截至 2016年8月, Webpack和Rollup被广泛认为比Browserify更好。)

鲍尔维护一个单一版本的模块,它只是试图帮助您为您select正确/最好的模块。

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

NPM对节点模块来说比较好,因为有一个模块系统,你在本地工作。 Bower对于浏览器来说是有好处的,因为目前只有全球范围的浏览器,而且你希望对你使用的版本非常有select性。

我的团队从鲍尔搬到npm,因为:

  • 程序化的使用是痛苦的
  • 鲍尔的界面不断变化
  • 一些function,如url速记,完全破碎
  • 在同一个项目中同时使用Bower和npm是痛苦的
  • 保持bower.json版本字段与git标签同步是痛苦的
  • 源代码pipe理!=程序包pipe理
  • CommonJS支持并不简单

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

http://ng-learn.org/2013/11/Bower-vs-npm/find这个有用的解释;

一方面,npm被创build用于安装在node.js环境中使用的模块,或者使用诸如Karma,lint,minifiers等的node.js构build的开发工具。 npm可以将模块本地安装在项目中(默认情况下是在node_modules中),也可以全局安装在多个项目中。 在大型项目中,指定依赖项的方法是创build一个名为package.json的文件,其中包含一个依赖关系列表。 当您运行npm install时,该列表被npm所识别,然后为您下载并安装它们。

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

正如你所看到的,虽然他们执行类似的任务,但他们的目标是一个非常不同的库。

对于许多使用node.js的人来说,bower的一个主要好处就是pipe理不是javascript的依赖关系。 如果他们正在使用编译为javascript的语言,则可以使用npm来pipe理其某些依赖关系。 但是,并不是所有的依赖都是node.js模块。 其中一些编译为JavaScript的可能会有怪异的源语言特定的损坏,使得在用户期待源代码时将它们编译为javascript是一个不合适的选项。

不是所有的npm包都需要面向用户的javascript,但是对于npm库包,至less应该有一些。