那么,npm和bow有什么区别呢?

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

327883 次浏览

所有的包管理器都有很多缺点。你只需要选择你能忍受的。

历史

npm开始管理node.js模块(这就是为什么包默认进入node_modules),但当与浏览序列化webpack组合时,它也适用于前端。

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

回购规模

npm比bwer大得多,包括通用JavaScript(如用于国家信息的country-data或用于前端或后端可用的排序函数的sorts)。

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

风格处理等

鲍尔包括风格等。

npm专注于JavaScript。样式要么单独下载,要么被npm-sasssass-npm之类的东西要求。

依赖处理

最大的区别是npm做嵌套依赖(但默认情况下是扁平的),而鲍尔需要一个扁平的依赖树(将依赖解决的负担放在用户身上)

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

一些项目同时使用两者:他们将Bwer用于前端包,将npm用于Yeoman、Grunt、Gulp、JSHint、CoffeeScript等开发工具。


资源

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

JavaScript依赖管理:npm vs bors vs volo?

NPM对于节点模块更好,因为有一个模块系统并且您在本地工作。鲍尔对浏览器有好处,因为目前只有全局范围,你想对你使用的版本非常有选择性。

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

一方面,npm被创建来安装在node.js环境中使用的模块,或者使用node.jsKarma、lint、mini等构建的开发工具。npm可以在项目中本地安装模块(默认node_modules)或全局安装模块以供多个项目使用。在大型项目中,指定依赖项的方法是创建一个名为package.json的文件,其中包含依赖项列表。当你运行npm install时,npm会识别该列表,然后为你下载并安装它们。

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

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

对于许多使用node.js的人来说,bwer的一个主要好处是管理根本不是javascript的依赖项。如果他们使用编译为javascript的语言,npm可以用来管理他们的一些依赖项。然而,并不是所有的依赖项都将node.js模块。一些编译为javascript的依赖项可能有奇怪的源语言特定的修饰,这使得当用户期待源代码时,传递它们编译为javascript是一个不优雅的选择。

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

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

npm常见问题(archive.org链接从6 Sep 2015)

没有嵌套就很难避免依赖冲突依赖关系。这是npm工作方式的基础,并且具有这是一个非常成功的方法

鲍尔

鲍尔针对前端进行了优化。鲍尔使用平面依赖树,每个包只需要一个版本,减少页面负载最小化

简而言之,npm旨在稳定性。鲍尔旨在最小化资源负载。如果你画出依赖结构,你会看到:

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呢?

npm会同时安装此依赖项的两个版本,因此无论如何它都可以工作,但是鲍尔会给你一个冲突,因为它不喜欢重复(因为在网页上加载相同的资源是非常低效和昂贵的,而且它会给你一些严重的错误)。你必须手动选择要安装的版本。这可能会产生其中一个依赖项会中断的效果,但无论如何你都需要修复这一点。

因此,常见的用法是Bwer,用于您要在网页上发布的包(例如运行时,避免重复),并将npm用于其他内容,如测试,构建,优化,检查等(例如开发时间,重复不太受关注)。

更新npm 3:

npm 3的做法与Bwer不同。它将全局安装依赖项,但仅限于它遇到的第一个版本。其他版本安装在树中(父模块,然后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(此版本与根版本不同,因此它将是嵌套安装)

有关更多信息,我建议阅读npm3相关文档

我的团队离开了鲍尔并迁移到npm,因为:

  • 编程使用是痛苦的
  • 鲍尔的界面一直在变
  • 一些功能,如网址速记,完全损坏
  • 在同一个项目中同时使用鲍尔和npm是很痛苦的
  • 保持bower.json版本字段与git标签同步是很痛苦的
  • 源代码控制!=包管理
  • 但是,对UserJS的支持并不简单

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

2017-Oct更新

鲍尔终于是已弃用。故事结束了。

老答案

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

在几乎所有情况下,使用Browserfy和npm而不是B伤脑筋都更合适。对于前端应用程序来说,它只是比鲍尔更好的打包解决方案。在Spotify,我们使用npm来打包整个Web模块(html、css、js),并且效果非常好。

鲍尔将自己标榜为网络包管理器。如果这是真的,那就太棒了——一个让我作为前端开发人员的生活变得更好的包管理器将是太棒了。问题是鲍尔没有为此提供专门的工具。据我所知,它没有提供npm没有的工具,尤其是没有一个对前端开发人员特别有用的工具。对于前端开发人员来说,在npm上使用Bwer根本没有任何好处。

我们应该停止使用鲍尔并围绕npm进行整合。谢天谢地,这就是正在发生

模块计数-鲍尔与npm

有了浏览器或webpack,将你的所有模块连接成大的缩小文件变得非常容易,这对性能来说非常棒,尤其是对于移动设备来说。而鲍尔就不是这样了,它需要更多的劳动力才能达到同样的效果。

npm还提供了同时使用多个版本的模块的能力。如果你没有做过太多的应用程序开发,这最初可能会让你觉得这是一件坏事,但是一旦你经历了几次依赖地狱,你就会意识到拥有一个模块的多个版本的能力是一个非常棒的特性。请注意,npm包括一个非常方便的消重工具,它会自动确保你只使用一个模块的两个版本,如果你实际上到-如果两个模块可以都使用一个模块的相同版本,他们会。但是如果他们不能,你有一个非常方便的出路。

(请注意,截至2016年8月,webpack汇总被广泛认为比Browserfy更好。

太长别读:日常使用中最大的区别不是嵌套依赖……而是模块和全局变量之间的区别。

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

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

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

鲍尔方法:全球资源,如<script>标签

在根程序中,鲍尔是关于加载普通的脚本文件。无论这些脚本文件包含什么,鲍尔都会加载它们。这基本上意味着鲍尔就像在超文本标记语言的<head>中包含所有普通的<script>脚本一样。

因此,与您习惯的基本方法相同,但您可以获得一些不错的自动化便利:

  • 你曾经需要在项目存储库中包含JS依赖项(在开发时),或者通过CDN获取它们。现在,你可以跳过存储库中额外的下载权重,有人可以快速bower install并立即在本地获得他们需要的东西。
  • 如果鲍尔依赖项在其bower.json中指定了自己的依赖项,那么这些依赖项也将为您下载。

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

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

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

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

  • 模块内的任何内容实际上都是命名空间,这意味着它不再是全局变量,并且您不能意外地引用它而不打算。
  • 模块中的任何内容都必须有意地注入到特定的上下文(通常是另一个模块)中才能使用它
  • 这意味着你可以在应用程序的不同部分拥有同一外部依赖项的多个版本(比方说Lodash),它们不会发生冲突/冲突。(这种情况经常发生,因为你自己的代码想要使用一个版本的依赖项,但你的一个外部依赖项指定了另一个冲突。或者你有两个外部依赖项,每个都想要不同的版本。)
  • 因为所有依赖项都是手动注入到特定模块中的,所以很容易推理它们。
  • 因为即使是注入模块的内容在你分配给它的变量后面,也是封装,而且所有代码都在有限的范围内执行,所以意外和冲突变得非常不可能。你的一个依赖项中的某个东西在你意识到的情况下意外地重新定义全局变量的可能性要小得多,或者你会这样做的可能性要小得多。(它会发生可以,但你通常必须不遗余力地去做,比如window.variable。仍然容易发生的一个事故是分配this.variable,没有意识到this实际上是当前上下文中的window。)
  • 当你想测试单个模块时,你可以很容易地知道:还有什么(依赖项)影响了模块内运行的代码?而且,因为你显式注入了所有内容,你可以很容易地模拟这些依赖项。

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


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

var React = require('react');

在文件/模块内部,您可以做任何您通常会做的事情,并创建一些您希望向外部用户公开的对象或函数,可能将其命名为myModule

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

module.exports = myModule;

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

而且,由于ES6模块(您可能会使用Babel或类似工具转译为ES5)正在获得广泛接受,并且可以在浏览器或Node 4.0中运行,我们也应该提到其中的良好的概述

更多关于在这个甲板中使用模块的模式。


编辑(2017年2月):Facebook的纱线是如今npm非常重要的潜在替代品/补充:基于npm为您提供的快速、确定性、离线包管理。任何JS项目都值得一看,特别是因为它很容易换入/换出。


编辑(2019年5月)“鲍尔终于是已弃用。故事结束了。”(h/t:@DanDascalescu,下面,用于简洁的总结。)

而且,虽然Yarn仍然活跃,但一旦它采用了Yarn的一些关键特性,它的很多动力就会转移回npm。