bower
和之间的根本区别是npm
什么?只需要简单明了的东西。我已经看到一些同事在他们的项目中使用bower
和npm
互换使用。
所有程序包管理器都有很多缺点。您只需要选择可以与之同住的即可。
历史
npm开始管理node.js模块(这就是node_modules
默认情况下会放入软件包的原因),但是当与Browserify或webpack结合使用时,它也适用于前端。
Bower是专门为前端创建的,因此考虑到了优化。
回购规模
npm比bower大得多,包括通用JavaScript(例如country-data
用于国家/地区信息或sorts
用于在前端或后端使用的排序功能)的Bower得多。
Bower的包装数量要少得多。
样式等的处理
凉亭包括样式等。
npm专注于JavaScript。样式为单独下载或类似的东西需要npm-sass
或sass-npm
。
依赖处理
最大的区别是npm确实嵌套了依赖项(但默认情况下是平坦的),而Bower需要平坦的依赖关系树(这给用户解决了依赖项的负担)。
嵌套的依赖关系树意味着您的依赖关系可以具有自己的依赖关系,也可以具有自己的依此类推。这允许两个模块要求具有相同依赖项的不同版本,并且仍然可以工作。请注意,从npm v3开始,默认情况下,依赖项树将保持平坦(节省空间),并且仅在需要的地方嵌套,例如,如果两个依赖项需要它们自己的Underscore版本。
一些项目同时使用这两种方法,即它们将Bower用于前端软件包,将npm用于开发人员工具,例如Yeoman,Grunt,Gulp,JSHint,CoffeeScript等。
资源资源
- 嵌套依赖关系 -深入了解node_modules的工作方式
此答案是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)。
- [node_modules]
- Dep A v1.0
- 部门B v1.0
Dep A v1.0(使用根版本)
- Dep C v1.0
- dep A v2.0(此版本与根版本不同,因此它将是嵌套安装)
TL; DR:日常使用中最大的区别不是嵌套的依赖关系……而是模块和全局变量之间的区别。
我认为以前的海报涵盖了一些基本区别。(npm使用嵌套依赖关系确实对管理大型,复杂的应用程序非常有帮助,尽管我认为这不是最重要的区别。)
但是,令我惊讶的是,没有人明确解释Bower和npm之间最根本的区别之一。如果您阅读上面的答案,将会在npm的上下文中看到经常使用的“模块”一词。但是它被随意提及,好像它可能只是语法上的区别。
但是,模块与全局变量(或模块与“脚本”)之间的区别可能是Bower与npm之间最重要的区别。将所有内容放入模块的npm方法要求您更改为浏览器编写Javascript的方式,几乎可以肯定,这样做会更好。
鲍尔方法:像<script>
标签一样的全球资源
从根本上说,Bower与加载普通的脚本文件有关。无论这些脚本文件包含什么,Bower都将加载它们。这基本上意味着鲍尔就像包括普通老式所有脚本<script>
的在<head>
你的HTML中。
因此,您使用了相同的基本方法,但是却获得了一些不错的自动化便利:
- 您曾经需要在开发过程中在项目存储库中包含JS依赖项,或者通过CDN获得它们。现在,您可以跳过存储库中多余的下载内容,因此有人可以
bower install
在本地快速快速地获得所需的内容。 - 如果Bower依赖项随后在中指定了自己的依赖项,那么这些
bower.json
链接也将为您下载。
但除此之外,Bower不会改变我们编写javascript的方式。Bower加载的文件内部没有任何变化。特别是,这意味着Bower加载的脚本中提供的资源(通常但并非总是如此)仍将定义为全局变量,可以从浏览器执行上下文中的任何位置使用。
npm方法:通用JS模块,显式依赖注入
Node领域中的所有代码(以及因此所有通过npm加载的代码)都被构造为模块(具体而言,作为CommonJS模块格式的实现,或现在成为ES6模块)。因此,如果您使用NPM处理浏览器端的依赖关系(通过Browserify或执行相同工作的其他方式),则将以与Node相同的方式来构造代码。
比我解决“为什么要使用模块?”问题的人要聪明,但这是一个总结:
- 模块内部的任何内容都有效地命名为,这意味着它不再是全局变量,并且您不能无意间无意地引用它。
- 必须有意将模块内部的任何内容注入特定的上下文(通常是另一个模块)中才能使用它
- 这意味着您可以在应用程序的各个部分中具有相同外部依赖项的多个版本(比如说破折号),它们不会发生冲突/冲突。(这经常出乎意料地发生,因为您自己的代码想要使用一个版本的依赖关系,但是您的一个外部依赖关系指定了另一个冲突的版本。或者您有两个外部依赖关系,每个都需要一个不同的版本。)
- 由于所有依赖项都是手动注入到特定模块中的,因此很容易就可以对它们进行推理。您知道一个事实:“在进行此操作时,我唯一需要考虑的代码就是我故意选择在此处注入的代码”。
- 因为即使注入模块的内容都封装在您为其分配的变量之后,并且所有代码都在有限范围内执行,所以意外和冲突变得非常不可能。如果您没有意识到,您依赖项之一中的某些内容会意外地重新定义全局变量的可能性要小得多,或者您会这样做。(它可能发生,但是您通常必须采取类似的方式
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。
2017年10月更新
鲍尔终于被弃用了。故事结局。
较旧的答案
来自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包含一个非常方便的重复数据删除工具,如果确实需要,它会自动确保仅使用模块的两个版本-如果两个模块都可以使用一个模块的相同版本,则将使用。但是,如果他们做不到,那么您将非常方便。
(请注意,截至 2016年8月,Webpack和汇总功能被认为比Browserify更好。)
Bower维护模块的单一版本,它仅尝试帮助您为您选择正确/最佳的模块。
NPM对于节点模块更好,因为存在模块系统并且您在本地工作。Bower对浏览器很有用,因为当前只有全局范围,并且您希望对使用的版本非常有选择性。
我的团队从Bower搬到了npm,原因是:
- 程序化使用很痛苦
- Bower的界面不断变化
- 某些功能(如url速记)已完全损坏
- 在同一项目中同时使用Bower和npm会很痛苦
- 使bower.json版本字段与git标签保持同步是很痛苦的
- 源代码控制!=包管理
- CommonJS支持并不简单
有关更多详细信息,请参见“为什么我的团队使用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库软件包,至少其中一些应该是。
文章标签:bower , javascript , npm
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!