繁体   English   中英

Bower 和 npm 有什么区别?

[英]What is the difference between Bower and npm?

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

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

历史

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

Bower专为前端创建,并考虑到这一点进行了优化。

回购规模

NPM是多少,比亭子,包括通用的JavaScript大得多(如country-data为国家信息或sorts用于分拣功能是在前端或后端可用)。

Bower 的包数量要少得多。

样式处理等

Bower 包括样式等。

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

依赖处理

最大的区别是 npm 做嵌套依赖(但默认是扁平的),而 Bower 需要扁平的依赖树(把依赖解析的负担放在用户身上)

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

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


资源

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

因此,常见的用法是 Bower 用于您要在网页上发布的包(例如运行时,避免重复),并使用 npm 用于其他内容,例如测试、构建、优化、检查等(例如开发时间) ,其中重复问题较少)。

npm 3 的更新:

与 Bower 相比,npm 3 的处理方式仍然不同。 它将全局安装依赖项,但仅适用于它遇到的第一个版本。 其他版本安装在树中(父模块,然后是 node_modules)。

  • [节点模块]
    • 深度 A v1.0
    • 深度 B v1.0
      • 深度 A v1.0 (使用根版本)
    • DEP C v1.0
      • dep A v2.0(这个版本和root版本不一样,所以会嵌套安装)

有关更多信息,我建议阅读npm 3文档

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

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

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

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

Bower 方法:全局资源,如<script>标签

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

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

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

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

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

Node 中的所有代码(以及所有通过 npm 加载的代码)都被构建为模块(具体来说,作为CommonJS 模块格式的实现,或者现在作为 ES6 模块)。 因此,如果您使用 NPM 来处理浏览器端的依赖项(通过 Browserify 或其他可以完成相同工作的东西),您将按照 Node 的方式构建代码。

比我更聪明的人已经解决了“为什么是模块?”的问题,但这里有一个简单的总结:

  • 模块内的任何内容都是有效的命名空间,这意味着它不再是全局变量,并且您不会无意中意外引用它。
  • 模块内的任何内容都必须有意注入到特定上下文(通常是另一个模块)中才能使用它
  • 这意味着您可以在应用程序的各个部分拥有相同外部依赖项(例如 lodash)的多个版本,并且它们不会发生冲突/冲突。 (这种情况出人意料地经常发生,因为您自己的代码想要使用一个版本的依赖项,但是您的一个外部依赖项指定了另一个冲突。或者您有两个外部依赖项,每个都需要不同的版本。)
  • 因为所有依赖项都是手动注入到特定模块中的,所以很容易推断它们。 您知道一个事实: “我在处理此问题时需要考虑的唯一代码是我有意选择在此处注入的代码”
  • 因为即使是注入模块的内容也被封装在您分配给它的变量后面,并且所有代码都在有限的范围内执行,所以意外和冲突变得非常不可能。 来自您的依赖项之一的某些内容在您没有意识到的情况下意外地重新定义全局变量的可能性要小得多,或者您会这样做。 (它可以发生,但你通常要走出自己的方式做到这一点,喜欢的东西window.variable 。在一个偶然的还是趋向于发生是分配this.variable ,却没有意识到this实际上是window在当前语境。)
  • 当您想测试单个模块时,您可以很容易地知道:究竟还有什么(依赖项)影响了在模块内运行的代码? 而且,因为您显式地注入了所有内容,所以您可以轻松地模拟这些依赖项。

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


学习如何使用 CommonJS/Node 模块语法只需要大约 30 秒。 在一个给定的 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 月更新

Bower 终于被弃用了 故事结局。

较旧的答案

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

在几乎所有情况下,使用 Browserify 和 npm 比 Bower 更合适。 它只是比 Bower 更好的前端应用程序打包解决方案。 在 Spotify,我们使用 npm 来打包整个 Web 模块(html、css、js),并且效果很好。

Bower 将自己打造成网络包管理器。 如果这是真的,那就太棒了 - 一个让我作为前端开发人员的生活变得更好的包管理器会很棒。 问题是 Bower 没有为此提供专门的工具。 它没有提供我知道 npm 没有的任何工具,尤其是没有提供对前端开发人员特别有用的工具。 前端开发人员在 npm 上使用 Bower 没有任何好处。

我们应该停止使用 bower 并围绕 npm 进行整合。 值得庆幸的是,这就是正在发生的事情

模块数量 - bower 与 npm

使用 browserify 或 webpack,将所有模块连接成大的缩小文件变得非常容易,这对性能来说非常棒,尤其是对于移动设备。 Bower 并非如此,这将需要更多的劳动力才能获得相同的效果。

npm 还使您能够同时使用多个版本的模块。 如果你没有做过很多应用程序开发,这最初可能会让你觉得这是一件坏事,但是一旦你经历了几次依赖地狱,你就会意识到拥有一个模块的多个版本的能力是一件非常糟糕的事情很棒的功能。 需要注意的是NPM包括一个非常方便的重复数据删除工具,可自动确保您只使用一个模块的两个版本,如果你确实-如果两个模块都可以使用一个模块的版本相同,他们会的。 但如果他们不能,你有一个非常方便的。

(请注意, 截至2016 年 8 月,人们普遍认为Webpackrollup比 Browserify 更好。)

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

Javascript 依赖管理:npm vs bower vs volo?

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 识别,然后它会为您下载并安装它们。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM