Bower和npm有什么区别?

时间:2013-09-05 16:53:20

标签: javascript npm bower

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

9 个答案:

答案 0 :(得分:1875)

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

历史

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

Bower仅针对前端创建,并针对此进行了优化。

回购的大小

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

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

处理样式等

Bower包括款式等。

npm专注于JavaScript。样式可以单独下载,也可以通过npm-sasssass-npm等方式下载。

依赖性处理

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

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

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


资源

答案 1 :(得分:355)

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

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

因此,对于要在网页上发布的软件包(例如运行时,在哪里避免重复),常见用法是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(此版本与根版本不同,因此它将是嵌套安装)

有关详细信息,建议您阅读docs of npm 3

答案 2 :(得分:264)

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

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

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

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

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

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

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

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

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

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

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

比我更聪明的人解决了为什么模块的问题?&#39;,但这是一个胶囊摘要:

  • 模块内部的任何内容实际上都是 namespaced ,这意味着它不再是全局变量,并且您无法在不打算的情况下意外引用它。
  • 模块内的任何内容都必须有意地注入特定的上下文(通常是另一个模块)才能使用它
  • 这意味着您可以在应用程序的各个部分中拥有相同外部依赖项的多个版本(lodash,让我们说),并且它们不会发生冲突/冲突。 (这种情况经常发生,因为您自己的代码想要使用一个版本的依赖项,但是您的一个外部依赖项指定了另一个冲突。或者您有两个外部依赖项,每个都需要不同的版本。)
  • 因为所有依赖项都是手动注入特定模块的,所以很容易对它们进行推理。你知道一个事实:&#34;我在处理这个问题时需要考虑的唯一代码就是我故意选择在这里注入&#34;
  • 因为即使注入模块的内容封装在您指定的变量后面,并且所有代码都在有限的范围内执行,所以意外和冲突变得非常不可能。它很多,不太可能是你的某个依赖项中的某些东西会在你没有意识到的情况下意外地重新定义一个全局变量,或者你会这样做。 (可以发生,但你通常不得不用window.variable之类的东西来做这件事。仍然会发生的一件事是分配this.variable ,没有意识到当前上下文中this实际上是window。)
  • 当您想要测试单个模块时,您可以非常容易地知道:究竟还有哪些(依赖项)正在影响模块内部运行的代码?并且,因为您明确地注入了所有内容,所以您可以轻松地模拟这些依赖项。

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

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

var React = require('react');

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

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

module.exports = myModule;

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

AND,因为ES6模块(您可能会通过Babel或类似程序转发到ES5)正在获得广泛接受,并且在浏览器或Node 4.0中都可以使用,我们应该提到good overview那些也是。

有关在this deck中使用模块的模式的更多信息。

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

编辑(2019年5月) &#34;鲍尔终于deprecated了。故事的结尾。&#34; (h / t:@DanDascalescu,下面,简明扼要。)

而且,虽然Yarn is still active,一旦它采用了Yarn的一些主要功能,它的很多动力都会转回到npm。

答案 3 :(得分:126)

2017年10月更新

鲍尔终于deprecated了。故事结束。

旧答案

From Mattias Petter Johansson, JavaScript developer at Spotify

  

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

     

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

     

我们应该停止使用凉亭并在npm周围进行整合。值得庆幸的是,这就是is happening

Module counts - bower vs. npm

  

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

     

npm还可以同时使用多个版本的模块。如果你没有做太多的应用程序开发,这可能最初会让你感到害怕,但是一旦你经历了一些Dependency hell的比赛,你就会发现有能力拥有多个版本的一个模块是一个非常好的功能。请注意,npm包含一个非常方便的dedupe tool,如果您实际拥有,则会自动确保您只使用模块的两个版本 - 如果两个模块都可以使用相同版本的一个模块,他们会。但如果他们无法,你就会非常方便。

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

答案 4 :(得分:45)

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

  

Javascript dependency management : npm vs bower vs volo?

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

答案 5 :(得分:33)

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

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

有关详细信息,请参阅"Why my team uses npm instead of bower"

答案 6 :(得分:16)

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

     

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

答案 7 :(得分:7)

对于使用node.js的许多人来说,bower的一个主要好处是管理非javascript的依赖项。如果他们使用编译为javascript的语言,则可以使用npm来管理他们的一些依赖项。但是,并非所有的依赖项都是node.js模块。编译为javascript的一些可能具有奇怪的源语言特定的修改,使得当用户期望源代码时,将它们编译为javascript是一个不优雅的选项。

并非npm包中的所有内容都需要面向用户的javascript,但对于npm库包,至少应该有一些。

答案 8 :(得分:3)

Bower和Npm是javascript的软件包管理器。在应该使用Bower或Npm的地方有很多困惑。一些项目同时具有Npm和Bower。在这里,我已经解释了这两种工具的用途,您将了解必须在何处使用Bower,在何处使用npm。

下堡

Bower是为专门为前端开发而创建的,并且已将其优化。它使用平面依赖树,每个包仅需要一个版本,从而减少了页面负载。主要目的是最小化资源负载。

Bower有一个名为bower.json的配置文件。在此文件中,我们可以维护Bower的配置,例如我们需要哪些依赖项以及许可证详细信息,描述,名称等。

Bower适用于诸如jQuery,Angular,React,Ember,Knockout,Bridge等前端软件包。

Npm(节点程序包管理器)

Npm最常用于管理Node.js模块,但它也适用于前端。它使用嵌套的依赖关系树,这意味着您的依赖关系可以具有自己的依赖关系,也可以具有自己的依此类推。嵌套的依赖关系树意味着您的依赖关系可以具有自己的依赖关系,也可以具有自己的依此类推。在服务器上,您不必太在乎空间和延迟,这真的很棒。

这显然在前端不能很好地工作,因为我们在项目中需要jQuery。我们只需要一个jQuery副本,但是当另一个软件包需要jQuery时,它将再次下载jQuery的另一个副本。这是Npm的主要缺点之一。

Npm有一个名为package.json的配置文件。在此文件中,我们可以维护Npm的配置,例如我们需要哪些依赖项以及许可证详细信息,描述,名称等。 Npm提供了依赖关系和DevDependencies。 依赖关系将下载并维护前端文件,例如Jquery,Angular等。 DevDependencies 将下载并维护开发工具,例如Grunt,Gulp,JSHint等。

许多项目同时使用的原因是,他们将Bower用于前端软件包,将Npm用于开发人员工具,例如Grunt,Gulp,JSHint等。