协慌网

登录 贡献 社区

Bower 和 npm 有什么区别?

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

答案

所有包管理器都有许多缺点。你只需挑选你可以忍受的东西。

历史

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

Bower专为前端而设计,并在此基础上进行了优化。

回购的大小

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

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

处理款式等

凉亭包括款式等。

npm 专注于 JavaScript。样式可以单独下载,也可以通过npm-sasssass-npm

依赖性处理

最大的区别是 npm 执行嵌套依赖项(但默认情况下是平坦的),而 Bower 需要一个平面依赖树(将依赖项解析的负担放在用户身上)

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

有些项目同时使用 Bower 作为前端软件包,npm 用于开发人员工具,如 Yeoman,Grunt,Gulp,JSHint,CoffeeScript 等。


资源

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

npm FAQ :( archive.org 链接从 2015 年 9 月 6 日)

如果没有嵌套依赖关系,就很难避免依赖冲突。这是 npm 工作方式的基础,并且已被证明是一种非常成功的方法。

Bower主页上:

Bower 针对前端进行了优化。 Bower 使用平面依赖树,每个包只需要一个版本,从而将页面加载降至最低。

简而言之,npm 旨在稳定。 Bower 的目标是最小的资源负荷。如果你绘制出依赖结构,你会看到:

故宫:

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 更新:

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

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

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

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

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

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

凉亭方法:全球资源,像<script>标签

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

所以,你已经习惯了相同的基本方法,但是你获得了一些很好的自动化方便:

  • 您曾经需要在项目仓库中包含 JS 依赖项(在开发时),或者通过 CDN 获取它们。现在,您可以在回购中跳过额外的下载权重,并且有人可以快速bower install并立即在本地获得所需内容。
  • 如果 Bower 依赖项然后在其bower.json指定自己的依赖bower.json ,那么也会为您下载这些依赖项。

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

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

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

聪明的人比我解决 '为什么模块?' 的问题,但这是一个胶囊摘要:

  • 模块内部的任何东西都是有效的命名空间 ,这意味着它不再是一个全局变量,并且你不能在没有意图的情况下意外地引用它。
  • 模块内的任何内容都必须有意地注入特定的上下文(通常是另一个模块)才能使用它
  • 这意味着您可以在应用程序的各个部分中拥有相同外部依赖项的多个版本(例如,lodash),它们不会发生冲突 / 冲突。 (这种情况经常发生,因为您自己的代码想要使用一个版本的依赖项,但是您的一个外部依赖项指定了另一个冲突。或者您有两个外部依赖项,每个都需要不同的版本。)
  • 因为所有依赖项都是手动注入特定模块的,所以很容易对它们进行推理。你知道一个事实: “我在这方面需要考虑的唯一代码就是我故意选择在这里注入”
  • 因为即使注入模块的内容被封装在您分配给它的变量后面,并且所有代码都在有限的范围内执行,所以惊喜和冲突变得非常不可能。很可能,你的某个依赖项中的某些内容会在没有意识到的情况下意外地重新定义全局变量,或者你会这样做。 (它可能会发生,但你通常不得不用你的方式去做,像window.variable这样的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 的纱线是当今 npm 非常重要的潜在替代 / 补充:快速,确定性,离线包管理,建立在 npm 为您提供的基础上。值得一看任何 JS 项目,特别是因为它很容易交换进 / 出。