所有程序包管理器都有很多缺点。您只需要选择可以忍受的内容即可。
npm开始管理 node.js 模块(这就是为什么软件包默认进入node_modules
的原因),但是当与Browserify或webpack结合使用时,它也适用于前端。
Bower是专门为前端创建的,并且考虑到这一点已进行了优化。
NPM 是多少,比亭子,包括通用的 JavaScript 大得多(如country-data
为国家信息或sorts
用于分拣功能是在前端或后端可用)。
Bower 的包装数量要少得多。
凉亭包括样式等。
npm 专注于 JavaScript。样式要么单独下载,要么需要npm-sass
或sass-npm
类的样式。
最大的区别是 npm 确实嵌套了依赖项(但默认情况下是平坦的),而 Bower 需要平坦的依赖项树(这给用户带来了依赖项解决的负担) 。
嵌套的依赖关系树意味着您的依赖关系可以具有自己的依赖关系,也可以具有自己的依此类推。这允许两个模块要求具有相同依赖项的不同版本,并且仍然可以工作。请注意,从 npm v3 开始,依赖项树默认情况下将是扁平的(节省空间),并且仅在需要的地方嵌套,例如,如果两个依赖项需要它们自己的 Underscore 版本。
一些项目同时使用这两种方法,即它们将 Bower 用于前端软件包,将 npm 用于开发人员工具,例如 Yeoman,Grunt,Gulp,JSHint,CoffeeScript 等。
此答案是 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)。
TL; DR:日常使用中最大的区别不是嵌套的依赖关系…… 而是模块和全局变量之间的区别。
我认为以前的海报涵盖了一些基本区别。 (npm 使用嵌套依赖关系确实对管理大型,复杂的应用程序非常有帮助,尽管我认为这不是最重要的区别。)
但是,令我惊讶的是,没有人明确解释 Bower 和 npm 之间最根本的区别之一。如果您阅读上面的答案,将会在 npm 的上下文中看到经常使用的 “模块” 一词。但是它被随意提及,好像它可能只是语法上的区别。
但是, 模块与全局 (或模块与 “脚本”)之间的区别可能是 Bower 与 npm 之间最重要的区别。 将所有内容放入模块的 npm 方法要求您更改为浏览器编写 Javascript 的方式,几乎可以肯定,这样做会更好。
<script>
标签从根本上说,Bower 是关于加载普通脚本文件的。无论这些脚本文件包含什么,Bower 都将加载它们。基本上,这意味着 Bower 就像将所有脚本包含在 HTML 的<head>
中普通的<script>
中一样。
因此,您使用了相同的基本方法,但是却获得了一些不错的自动化便利:
bower install
并立即在本地获得所需的内容。 bower.json
指定了自己的依赖bower.json
,那么这些也将为您下载。 但是除此之外, Bower 不会改变我们编写 javascript 的方式 。 Bower 加载的文件内部没有任何变化。特别是,这意味着 Bower 加载的脚本中提供的资源(通常但并非总是如此)仍将定义为全局变量 ,可以从浏览器执行上下文中的任何位置使用。
Node 领域中的所有代码(以及因此所有通过 npm 加载的代码)都被构造为模块(具体来说,作为CommonJS 模块格式的实现 ,或者现在作为 ES6 模块)。因此,如果使用 NPM(通过 Browserify 或其他执行相同工作的方式)来处理浏览器端的依赖项,则将以与 Node 相同的方式来构造代码。
比我解决 “为什么要使用模块?” 问题的人要聪明,但这是一个总结:
window.variable
之类的方法来做到这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。
鲍尔终于被弃用了 。故事结局。
来自 Spotify JavaScript 开发人员 Mattias Petter Johansson :
在几乎所有情况下,更适合在 Bower 上使用 Browserify 和 npm。与 Bower 相比,它只是用于前端应用程序的更好的打包解决方案。在 Spotify,我们使用 npm 打包整个 Web 模块(html,css,js),并且效果很好。
Bower 将自己称为网络包装经理。如果真是这样,那真是太棒了 - 一个使我作为前端开发人员的生活更美好的软件包管理器将很棒。问题在于 Bower 没有为此目的提供专门的工具。它没有提供我不知道 npm 不能提供的工具,尤其是没有任何工具对前端开发人员特别有用。 对于前端开发人员而言,在 npm 上使用 Bower 根本没有任何好处。
我们应该停止使用凉亭并在 npm 左右合并。幸运的是,这是正在发生的事情 :
使用 browserify 或 webpack,将所有模块连接成较大的缩小文件变得非常容易,这对于性能(特别是对于移动设备)而言非常出色。 Bower 并非如此,Bower 需要更多的劳动力才能获得相同的效果。
npm 还使您能够同时使用多个版本的模块。如果您没有做太多的应用程序开发,那么一开始可能会遇到不好的事情,但是一旦您经历了几轮Dependency 地狱之后,您就会意识到拥有一个模块的多个版本的能力是很糟糕的。很棒的功能。请注意,npm 包含一个非常方便的重复数据删除工具 ,如果确实需要 ,它会自动确保仅使用模块的两个版本 - 如果两个模块都可以使用一个模块的相同版本,则它们将使用。但是,如果他们做不到 ,那么您将非常方便。
Bower 维护模块的单一版本,它仅尝试帮助您为您选择正确 / 最佳的模块。
NPM 对于节点模块更好,因为存在模块系统并且您在本地工作。 Bower 对浏览器很有用,因为当前只有全局范围,并且您希望对使用的版本非常有选择性。
我的团队从 Bower 搬到了 npm,原因是:
有关更多详细信息,请参见“为什么我的团队使用 npm 而不是 bower” 。
从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 的文件夹中。
如您所见,尽管它们执行相似的任务,但是它们针对的是一组非常不同的库。
对于许多使用 node.js 的人来说,bower 的主要好处是可以管理根本不是 JavaScript 的依赖项。如果他们使用可编译为 javascript 的语言,则 npm 可用于管理其某些依赖项。但是,并非所有依赖项都将是 node.js 模块。其中一些可编译为 javascript 的代码可能具有怪异的特定于源语言的修饰,这使得在用户期望源代码时,将它们传递给已编译为 javascript 的一个不明智的选择。
并非 npm 软件包中的所有内容都需要使用面向用户的 javascript,但是对于 npm 库软件包,至少其中一些应该是。