bower和npm的根本区别是什么?只想要简单明了的东西。我见过我的一些同事在他们的项目中交替使用bower和npm。
所有包管理器都有许多缺点。你只需要选择你能和谁一起生活。
历史
npm最初是管理node.js模块的(这就是为什么默认情况下包会进入node_modules),但当与Browserify或webpack结合时,它也适用于前端。
Bower专为前端而设计,并为此进行了优化。
回购规模
npm比bower大得多,包括通用JavaScript(如国家信息的国家数据或排序功能的排序,可在前端或后端使用)。
鲍尔的包裹数量要少得多。
样式处理等
Bower包括款式等。
npm专注于JavaScript。样式可以单独下载,也可以根据npm-sass或sas-npm等要求下载。
依赖关系处理
最大的区别是,npm执行嵌套依赖关系(但默认情况下是扁平的),而Bower需要一个扁平的依赖关系树(将依赖关系解析的负担推给用户)。
嵌套的依赖关系树意味着您的依赖关系可以有自己的依赖关系,这些依赖关系可以是自己的,依此类推。这允许两个模块需要相同依赖关系的不同版本,并且仍然可以工作。注意,自npm v3以来,依赖关系树默认为平面(节省空间),仅在需要时嵌套,例如,如果两个依赖关系需要自己的Undercore版本。
一些项目同时使用这两种工具:他们使用Bower作为前端包,使用npm作为开发工具,如Yeoman、Grunt、Gulp、JSHint、CoffeeScript等。
资源
嵌套依赖关系-深入了解node_modules的工作方式
Bower维护单一版本的模块,它只会帮助您选择正确/最佳的模块。
Javascript依赖管理:npm vs bower vs volo?
NPM对于节点模块更好,因为有一个模块系统,您在本地工作。Bower对浏览器很好,因为目前只有全局范围,您需要对所使用的版本非常有选择。
从中找到了此有用的解释http://ng-learn.org/2013/11/Bower-vs-npm/
一方面,创建npm是为了安装node.js环境中使用的模块,或使用node.js构建的开发工具,如Karma、lint、minifier等。npm可以在项目中本地安装模块(默认情况下在node_modules中),也可以在全局安装模块,供多个项目使用。在大型项目中,指定依赖项的方法是创建一个名为package.json的文件,其中包含依赖项列表。当您运行npm安装时,npm会识别该列表,然后下载并安装它们。另一方面,创建bower是为了管理前端依赖关系。jQuery、AngularJS、下划线等库。与npm类似,它有一个文件,您可以在其中指定一个名为bower.json的依赖项列表。在这种情况下,您的前端依赖项是通过运行bowerinstall来安装的,默认情况下,它会将它们安装在名为bowr_components的文件夹中。正如您所看到的,尽管它们执行类似的任务,但它们的目标是一组非常不同的库。
对于许多使用node.js的人来说,bower的一个主要好处是管理根本不是javascript的依赖关系。如果他们使用的是编译为javascript的语言,那么可以使用npm来管理他们的一些依赖关系。然而,并不是所有的依赖都是node.js模块。一些编译为javascript的代码可能有奇怪的源语言特定的篡改,这使得在用户期望源代码时,将它们传递给编译为javascript是一个不合适的选项。
并非npm包中的所有内容都需要面向用户的javascript,但对于npm库包,至少其中一些应该是面向用户的。
这个答案是对Sindre Sorhus答案的补充。npm和Bower之间的主要区别在于它们处理递归依赖关系的方式。请注意,它们可以在单个项目中一起使用。
关于npm常见问题解答:(archive.org链接,2015年9月6日)
如果没有嵌套,就很难避免依赖冲突依赖关系。这是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的更新:
与鲍尔相比,npm 3的表现仍然有所不同。它将全局安装依赖项,但仅适用于遇到的第一个版本。其他版本安装在树中(父模块,然后是node_modules)。
[节点模块]dep A v1.0版dep B v1.0版dep A v1.0(使用根版本)dep C v1.0版dep A v2.0(此版本与根版本不同,因此将是嵌套安装)
有关更多信息,我建议阅读npm 3的文档
我的团队从Bower搬到了npm,因为:
编程使用很痛苦Bower的界面不断变化有些功能,如url速记,完全被破坏了在同一项目中同时使用Bower和npm是很痛苦的保持bower.json版本字段与git标记同步非常困难源代码管理!=包裹管理CommonJS支持并不简单
有关详细信息,请参阅“为什么我的团队使用npm而不是bower”。
2017年10月更新
鲍尔终于被弃用了。故事结束。
较旧的答案
Spotify的JavaScript开发人员Mattias Petter Johansson:
在几乎所有情况下,在Bower上使用Browserify和npm更合适。它只是一个比Bower更好的前端应用打包解决方案。在Spotify,我们使用npm来打包整个web模块(html、css、js),而且效果非常好。Bower将自己打造为网络套餐管理者。如果这是真的,那就太棒了——一个能让我作为前端开发人员的生活变得更好的包管理器将太棒了。问题是Bower没有为此提供专门的工具。它提供了我所知的npm没有的任何工具,尤其是对前端开发人员没有特别有用的工具。前端开发人员在npm上使用Bower根本没有好处。我们应该停止使用bower,并围绕npm进行整合。谢天谢地,这就是正在发生的事情:
使用browserify或webpack,将所有模块连接到大的缩小文件中变得非常容易,这对于性能来说非常棒,尤其是对于移动设备。鲍尔则不然,这将需要更多的劳动力才能达到同样的效果。npm还可以同时使用多个版本的模块。如果你没有做过太多的应用程序开发,这可能最初会让你觉得是一件坏事,但一旦你经历了几次依赖性地狱,你就会意识到拥有一个模块的多个版本的能力是一个非常棒的功能。请注意,npm包含一个非常方便的重复数据消除工具,它可以自动确保您在实际需要时仅使用两个版本的模块-如果两个模块都可以使用同一版本的模块,则它们会使用。但如果他们做不到,你就有一个非常方便的解决方案。
(注意,截至2016年8月,Webpack和rollup被普遍认为比Browserify更好。)
TL;DR:日常使用中最大的区别不是嵌套依赖关系。。。这是模块和全局变量之间的区别。
我认为之前的海报很好地涵盖了一些基本的区别。(npm对嵌套依赖的使用确实非常有助于管理大型、复杂的应用程序,尽管我认为这不是最重要的区别。)
然而,我很惊讶,没有人明确解释鲍尔和npm之间最根本的区别之一。如果你阅读上面的答案,你会看到npm上下文中经常使用的单词“modules”。但这是随便提及的,好像它甚至可能只是语法上的差异。
但模块与全局(或模块与“脚本”)的区别可能是Bower和npm之间最重要的区别。将所有内容放入模块的npm方法要求您改变为浏览器编写Javascript的方式,几乎可以肯定是为了更好。
Bower方法:全球资源,如<script>标签
在根目录中,Bower负责加载普通的旧脚本文件。无论这些脚本文件包含什么,Bower都会加载它们。这基本上意味着Bower就像将所有脚本都包含在HTML的<head>中。
所以,这是您习惯的基本方法,但您可以获得一些很好的自动化便利:
您过去需要在项目库中包含JS依赖项(在开发时),或者通过CDN获取它们。现在,你可以跳过回购中的额外下载重量,有人可以快速安装bower,并立即在本地获得他们需要的内容。如果Bower依赖项随后在其Bower.json中指定了自己的依赖项,那么也会为您下载这些依赖项。
但除此之外,鲍尔并没有改变我们编写javascript的方式。Bower加载的文件中的内容根本不需要更改。特别是,这意味着Bower加载的脚本中提供的资源(通常,但不总是)仍然被定义为全局变量,可以从浏览器执行上下文中的任何位置获得。
npm方法:公共JS模块、显式依赖注入
Node land中的所有代码(以及通过npm加载的所有代码)都被构造为模块(具体来说,作为CommonJS模块格式的实现,或者现在作为ES6模块)。因此,如果您使用NPM来处理浏览器端的依赖关系(通过Browserify或其他执行相同任务的工具),那么您将以Node的方式构造代码。
比我更聪明的人解决了“为什么选择模块?”的问题,但这里有一个胶囊摘要:
模块中的任何内容都是有效的名称空间,这意味着它不再是一个全局变量,您不能无意中引用它。模块内的任何内容都必须有意地注入到特定上下文(通常是另一个模块)中,以便利用它这意味着您可以在应用程序的不同部分拥有相同外部依赖项(比如lodash)的多个版本,并且它们不会发生冲突。(这种情况经常发生,因为您自己的代码希望使用依赖项的一个版本,但您的一个外部依赖项指定了另一个冲突的版本。或者您有两个外部依赖关系,每个都需要不同的版本。)因为所有依赖项都是手动注入到特定模块中的,所以很容易理解它们。你知道一个事实:“在处理这个问题时,我需要考虑的唯一代码就是我有意选择在这里注入的代码”。因为甚至注入的模块的内容都封装在分配给它的变量后面,并且所有代码都在有限的范围内执行,所以意外和冲突变得非常不可能。在你没有意识到的情况下,你的一个依赖项中的某个东西会意外地重新定义一个全局变量,或者你会这样做。(这是可能发生的,但你通常必须用window.variable这样的方式去做。仍然会发生的一个意外是分配这个.variable,而没有意识到这实际上是当前上下文中的window。)当你想测试一个单独的模块时,你可以很容易地知道:到底还有什么(依赖关系)在影响模块内部运行的代码?而且,因为您显式地注入了所有内容,所以可以轻松地模拟这些依赖关系。
对我来说,前端代码模块的使用归结为:在更窄的环境中工作,更容易推理和测试,对发生的事情有更大的把握。
学习如何使用CommonJS/Node模块语法只需大约30秒。在将成为模块的给定JS文件中,首先声明要使用的任何外部依赖项,如下所示:
var React=要求(“响应”);
在文件/模块中,您可以做任何您通常会做的事情,并创建一些您希望向外部用户公开的对象或函数,称其为myModule。
在文件末尾,您可以导出任何您想与世界共享的内容,如下所示:
module.exports=myModule;
然后,要在浏览器中使用基于CommonJS的工作流,您将使用Browserify等工具抓取所有这些单独的模块文件,在运行时封装它们的内容,并根据需要将它们相互注入。
而且,由于ES6模块(您可能会使用Babel或类似工具将其转换为ES5)正在获得广泛接受,并且可以在浏览器或Node 4.0中使用,因此我们也应该对这些模块进行一个很好的概述。
有关使用本组模块的模式的更多信息。
编辑(2017年2月):Facebook的Yarn是当前npm的一个非常重要的潜在替代品/补充品:基于npm提供的快速、确定性、离线包管理。任何JS项目都值得一看,特别是因为它很容易进行交换。
编辑(2019年5月)“鲍尔终于被弃用了。故事结束了。”
而且,尽管Yarn仍然活跃,但一旦它采用了Yarn的一些关键功能,它的许多动力就转向了npm。
推荐文章
- 如何使用Jest测试对象键和值是否相等?
- 将长模板文字行换行为多行,而无需在字符串中创建新行
- 如何在JavaScript中映射/减少/过滤一个集?
- Bower: ENOGIT Git未安装或不在PATH中
- 添加javascript选项选择
- 在Node.js中克隆对象
- 为什么在JavaScript的Date构造函数中month参数的范围从0到11 ?
- 使用JavaScript更改URL参数并指定默认值
- 在window.setTimeout()发生之前取消/终止
- 如何删除未定义和空值从一个对象使用lodash?
- 检测当用户滚动到底部的div与jQuery
- 在JavaScript中检查字符串包含另一个子字符串的最快方法?
- 检测视口方向,如果方向是纵向显示警告消息通知用户的指示
- ASP。NET MVC 3 Razor:在head标签中包含JavaScript文件
- 禁用从HTML页面中拖动图像