javascript Bower 和 npm 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18641899/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between Bower and npm?
提问by Games Brainiac
What is the fundamental difference between bower
and npm
? Just want something plain and simple. I've seen some of my colleagues use bower
and npm
interchangeably in their projects.
bower
和之间的根本区别是npm
什么?只想要简单明了的东西。我看到我的一些同事在他们的项目中使用bower
和npm
互换。
回答by Sindre Sorhus
All package managers have many downsides. You just have to pick which you can live with.
所有的包管理器都有很多缺点。你只需要选择你可以忍受的。
History
历史
npmstarted out managing node.js modules (that's why packages go into node_modules
by default), but it works for the front-end too when combined with Browserifyor webpack.
npm开始管理 node.js 模块(这就是node_modules
默认情况下包进入的原因),但是当与Browserify或webpack结合使用时,它也适用于前端。
Boweris created solely for the front-end and is optimized with that in mind.
Bower专为前端创建,并考虑到这一点进行了优化。
Size of repo
回购规模
npm is much, much larger than bower, including general purpose JavaScript (like country-data
for country information or sorts
for sorting functions that is usable on the front end or the back end).
npm 比 bower 大得多,包括通用 JavaScript(例如country-data
用于国家信息或sorts
用于前端或后端可用的排序功能)。
Bower has a much smaller amount of packages.
Bower 的包数量要少得多。
Handling of styles etc
样式处理等
Bower includes styles etc.
Bower 包括样式等。
npm is focused on JavaScript. Styles are either downloaded separately or required by something like npm-sass
or sass-npm
.
npm 专注于 JavaScript。样式为单独下载或类似的东西需要npm-sass
或sass-npm
。
Dependency handling
依赖处理
The biggest difference is that npm does nested dependencies (but is flat by default) while Bower requires a flat dependency tree (puts the burden of dependency resolution on the user).
最大的不同是 npm 做嵌套依赖(但默认是扁平的),而 Bower 需要扁平的依赖树(把依赖解析的负担放在用户身上)。
A nested dependency tree means that your dependencies can have their own dependencies which can have their own, and so on. This allows for two modules to require different versions of the same dependency and still work. Note since npm v3, the dependency tree will by flat by default (saving space) and only nest where needed, e.g., if two dependencies need their own version of Underscore.
嵌套依赖树意味着您的依赖项可以拥有自己的依赖项,这些依赖项可以拥有自己的依赖项,依此类推。这允许两个模块需要相同依赖项的不同版本并且仍然可以工作。请注意,从 npm v3 开始,依赖树默认情况下是扁平的(节省空间)并且仅在需要的地方嵌套,例如,如果两个依赖项需要它们自己的 Underscore 版本。
Some projects use both is that they use Bower for front-end packages and npm for developer tools like Yeoman, Grunt, Gulp, JSHint, CoffeeScript, etc.
有些项目既使用 Bower 作为前端包,也使用 npm 作为开发工具,如 Yeoman、Grunt、Gulp、JSHint、CoffeeScript 等。
Resources
资源
- Nested Dependencies- Insight into why node_modules works the way it does
- 嵌套依赖- 深入了解 node_modules 的工作方式
回答by Justus Romijn
This answer is an addition to the answer of Sindre Sorhus. The major difference between npm and Bower is the way they treat recursive dependencies. Note that they can be used together in a single project.
这个答案是对 Sindre Sorhus 答案的补充。npm 和 Bower 之间的主要区别在于它们处理递归依赖的方式。请注意,它们可以在单个项目中一起使用。
On the npm FAQ:(archive.org link from 6 Sep 2015)
关于npm 常见问题:(archive.org 链接,2015 年 9 月 6 日)
It is much harder to avoid dependency conflicts without nesting dependencies. This is fundamental to the way that npm works, and has proven to be an extremely successful approach.
不嵌套依赖就很难避免依赖冲突。这是 npm 工作方式的基础,并且已被证明是一种非常成功的方法。
On Bowerhomepage:
在Bower主页上:
Bower is optimized for the front-end. Bower uses a flat dependency tree, requiring only one version for each package, reducing page load to a minimum.
Bower 针对前端进行了优化。Bower 使用扁平的依赖树,每个包只需要一个版本,将页面负载减少到最低限度。
In short, npm aims for stability. Bower aims for minimal resource load. If you draw out the dependency structure, you will see this:
简而言之,npm 的目标是稳定性。Bower 的目标是最小化资源负载。如果你画出依赖结构,你会看到:
npm:
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
As you can see it installs some dependencies recursively. Dependency A has three installed instances!
如您所见,它递归地安装了一些依赖项。依赖 A 已经安装了三个实例!
Bower:
凉亭:
project root
[bower_components] // default directory for dependencies
-> dependency A
-> dependency B // needs A
-> dependency C // needs B and D
-> dependency D
Here you see that all unique dependencies are on the same level.
在这里您会看到所有唯一的依赖项都在同一级别上。
So, why bother using npm?
那么,为什么要使用 npm 呢?
Maybe dependency B requires a different version of dependency A than dependency C. npm installs both versions of this dependency so it will work anyway, but Bower will give you a conflictbecause it does not like duplication (because loading the same resource on a webpage is very inefficient and costly, also it can give some serious errors). You will have to manually pick which version you want to install. This can have the effect that one of the dependencies will break, but that is something that you will need to fix anyway.
也许依赖项 B 需要一个与依赖项 C 不同版本的依赖项 A。 npm 安装了这个依赖项的两个版本,所以它无论如何都可以工作,但是 Bower 会给你一个冲突,因为它不喜欢重复(因为在网页上加载相同的资源是非常低效且成本高昂,还会产生一些严重的错误)。您必须手动选择要安装的版本。这可能会导致依赖项之一中断,但无论如何您都需要修复它。
So, the common usage is Bower for the packages that you want to publish on your webpages (e.g. runtime, where you avoid duplication), and use npm for other stuff, like testing, building, optimizing, checking, etc. (e.g. development time, where duplication is of less concern).
因此,常见的用法是 Bower 用于您要在网页上发布的包(例如运行时,避免重复),并将 npm 用于其他内容,例如测试、构建、优化、检查等(例如开发时间),其中重复问题较少)。
Update for npm 3:
npm 3 的更新:
npm 3 still does things differently compared to Bower. It will install the dependencies globally, but only for the first version it encounters. The other versions are installed in the tree (the parent module, then node_modules).
与 Bower 相比,npm 3 的处理方式仍然不同。它将全局安装依赖项,但仅针对它遇到的第一个版本。其他版本安装在树中(父模块,然后是 node_modules)。
- [node_modules]
- dep A v1.0
- dep B v1.0
dep A v1.0(uses root version)
- dep C v1.0
- dep A v2.0 (this version is different from the root version, so it will be an nested installation)
- [节点模块]
- 深度 A v1.0
- 深度 B v1.0
深度 A v1.0(使用根版本)
- DEP C v1.0
- dep A v2.0(此版本与root版本不同,所以会嵌套安装)
For more information, I suggest reading the docs of npm 3
回答by XML
TL;DR: The biggest difference in everyday use isn't nested dependencies... it's the difference between modules and globals.
TL;DR:日常使用中最大的区别不是嵌套依赖……而是模块和全局变量之间的区别。
I think the previous posters have covered well some of the basic distinctions. (npm's use of nested dependencies is indeed very helpful in managing large, complex applications, though I don't think it's the most important distinction.)
我认为之前的海报已经很好地涵盖了一些基本区别。(npm 使用嵌套依赖确实对管理大型复杂应用程序非常有帮助,尽管我认为这不是最重要的区别。)
I'm surprised, however, that nobody has explicitly explained one of the most fundamental distinctions between Bower and npm. If you read the answers above, you'll see the word 'modules' used often in the context of npm. But it's mentioned casually, as if it might even just be a syntax difference.
然而,令我惊讶的是,没有人明确解释 Bower 和 npm 之间最基本的区别之一。如果您阅读上述答案,您会看到 npm 上下文中经常使用的“模块”一词。但它被随意提及,好像它甚至可能只是一个语法差异。
But this distinction of modules vs. globals(or modules vs. 'scripts') is possibly the most important difference between Bower and npm. The npm approach of putting everything in modules requires you to change the way you write Javascript for the browser, almost certainly for the better.
但是这种模块与全局变量(或模块与“脚本”)的区别可能是 Bower 和 npm 之间最重要的区别。将所有内容放入模块的 npm 方法要求您更改为浏览器编写 Javascript 的方式,几乎肯定会变得更好。
The Bower Approach: Global Resources, Like <script>
Tags
Bower 方法:全球资源,如<script>
标签
At root, Bower is about loading plain-old script files. Whatever those script files contain, Bower will load them. Which basically means that Bower is just like including all your scripts in plain-old <script>
's in the <head>
of your HTML.
从根本上说,Bower 是关于加载普通的脚本文件。无论这些脚本文件包含什么,Bower 都会加载它们。这基本上意味着 Bower 就像将所有脚本包含在HTML中的普通<script>
's 中一样<head>
。
So, same basic approach you're used to, but you get some nice automation conveniences:
因此,与您习惯的基本方法相同,但您会获得一些不错的自动化便利:
- You used to need to include JS dependencies in your project repo (while developing), or get them via CDN. Now, you can skip that extra download weight in the repo, and somebody can do a quick
bower install
and instantly have what they need, locally. - If a Bower dependency then specifies its own dependencies in its
bower.json
, those'll be downloaded for you as well.
- 你曾经需要在你的项目 repo 中包含 JS 依赖项(在开发时),或者通过 CDN 获取它们。现在,您可以在 repo 中跳过额外的下载重量,并且有人可以
bower install
在本地快速并立即获得他们需要的东西。 - 如果 Bower 依赖项在其 中指定了自己的依赖项,那么这些依赖
bower.json
项也会为您下载。
But beyond that, Bower doesn't change how we write javascript. Nothing about what goes inside the files loaded by Bower needs to change at all. In particular, this means that the resources provided in scripts loaded by Bower will (usually, but not always) still be defined as global variables, available from anywhere in the browser execution context.
但除此之外,Bower 并没有改变我们编写 javascript 的方式。Bower 加载的文件中的内容根本不需要更改。特别是,这意味着 Bower 加载的脚本中提供的资源(通常,但不总是)仍将定义为全局变量,可从浏览器执行上下文的任何位置使用。
The npm Approach: Common JS Modules, Explicit Dependency Injection
npm 方法:通用 JS 模块,显式依赖注入
All code in Node land (and thus all code loaded via npm) is structured as modules (specifically, as an implementation of the CommonJS module format, or now, as an ES6 module). So, if you use NPM to handle browser-side dependencies (via Browserify or something else that does the same job), you'll structure your code the same way Node does.
Node 中的所有代码(以及所有通过 npm 加载的代码)都被构建为模块(具体来说,作为CommonJS 模块格式的实现,或者现在作为 ES6 模块)。因此,如果您使用 NPM 来处理浏览器端的依赖项(通过 Browserify 或其他可以完成相同工作的东西),您将按照 Node 的方式构建代码。
Smarter people than I have tackled the question of 'Why modules?', but here's a capsule summary:
比我更聪明的人已经解决了“为什么是模块?”的问题,但这里有一个简单的总结:
- Anything inside a module is effectively namespaced, meaning it's not a global variable any more, and you can't accidentally reference it without intending to.
- Anything inside a module must be intentionally injected into a particular context (usually another module) in order to make use of it
- This means you can have multiple versions of the same external dependency (lodash, let's say) in various parts of your application, and they won't collide/conflict. (This happens surprisingly often, because your own code wants to use one version of a dependency, but one of your external dependencies specifies another that conflicts. Or you've got two external dependencies that each want a different version.)
- Because all dependencies are manually injected into a particular module, it's very easy to reason about them. You know for a fact: "The only code I need to consider when working on this is what I have intentionally chosen to inject here".
- Because even the content of injected modules is encapsulatedbehind the variable you assign it to, and all code executes inside a limited scope, surprises and collisions become very improbable. It's much, much less likely that something from one of your dependencies will accidentally redefine a global variable without you realizing it, or that you will do so. (It canhappen, but you usually have to go out of your way to do it, with something like
window.variable
. The one accident that still tends to occur is assigningthis.variable
, not realizing thatthis
is actuallywindow
in the current context.) - When you want to test an individual module, you're able to very easily know: exactly what else (dependencies) is affecting the code that runs inside the module? And, because you're explicitly injecting everything, you can easily mock those dependencies.
- 模块内的任何内容都是有效的命名空间,这意味着它不再是全局变量,并且您不能无意中意外引用它。
- 模块内的任何内容都必须有意注入到特定上下文(通常是另一个模块)中才能使用它
- 这意味着您可以在应用程序的各个部分拥有相同外部依赖项(比如说 lodash)的多个版本,并且它们不会发生冲突/冲突。(这出乎意料地经常发生,因为您自己的代码想要使用一个版本的依赖项,但是您的一个外部依赖项指定了另一个冲突。或者您有两个外部依赖项,每个都需要不同的版本。)
- 因为所有依赖项都是手动注入到特定模块中的,所以很容易推断它们。您知道一个事实:“我在处理此问题时需要考虑的唯一代码是我有意选择在此处注入的代码”。
- 因为即使是注入模块的内容也被封装在您分配给它的变量后面,并且所有代码都在有限的范围内执行,所以意外和冲突变得非常不可能。来自您的依赖项之一的某些内容在您没有意识到的情况下意外地重新定义全局变量的可能性要小得多,或者您会这样做。(它可能发生,但你通常必须用你的方式去做,比如
window.variable
。仍然容易发生的一个事故是赋值this.variable
,没有意识到这this
实际上是window
在当前上下文中。) - 当您想测试单个模块时,您可以很容易地知道:究竟还有什么(依赖项)影响了在模块内运行的代码?而且,因为您明确地注入了所有内容,所以您可以轻松地模拟这些依赖项。
To me, the use of modules for front-end code boils down to: working in a much narrower context that's easier to reason about and test, and having greater certainty about what's going on.
对我来说,前端代码模块的使用归结为:在更窄的上下文中工作,更容易推理和测试,并且对正在发生的事情有更大的确定性。
It only takes about 30 seconds to learn how to use the CommonJS/Node module syntax. Inside a given JS file, which is going to be a module, you first declare any outside dependencies you want to use, like this:
学习如何使用 CommonJS/Node 模块语法只需要大约 30 秒。在一个给定的 JS 文件中,它将成为一个模块,你首先声明你想要使用的任何外部依赖项,如下所示:
var React = require('react');
var React = require('react');
Inside the file/module, you do whatever you normally would, and create some object or function that you'll want to expose to outside users, calling it perhaps myModule
.
在文件/模块内部,您可以做任何您通常会做的事情,并创建一些您希望向外部用户公开的对象或函数,可能将其称为myModule
.
At the end of a file, you export whatever you want to share with the world, like this:
在文件的末尾,您可以导出您想与世界分享的任何内容,如下所示:
module.exports = myModule;
module.exports = myModule;
Then, to use a CommonJS-based workflow in the browser, you'll use tools like Browserify to grab all those individual module files, encapsulate their contents at runtime, and inject them into each other as needed.
然后,要在浏览器中使用基于 CommonJS 的工作流,您将使用 Browserify 之类的工具来获取所有这些单独的模块文件,在运行时封装它们的内容,并根据需要将它们相互注入。
AND, since ES6 modules (which you'll likely transpile to ES5 with Babel or similar) are gaining wide acceptance, and work both in the browser or in Node 4.0, we should mention a good overviewof those as well.
而且,由于 ES6 模块(您可能会使用 Babel 或类似工具将其转换为 ES5)正在获得广泛接受,并且可以在浏览器或 Node 4.0 中运行,因此我们也应该对这些模块进行很好的概述。
More about patterns for working with modules in this deck.
更多关于使用本套牌中的模块的模式。
EDIT (Feb 2017): Facebook's Yarnis a very important potential replacement/supplement for npm these days: fast, deterministic, offline package-management that builds on what npm gives you. It's worth a look for any JS project, particularly since it's so easy to swap it in/out.
编辑(2017 年 2 月):如今,Facebook 的Yarn是 npm 非常重要的潜在替代品/补充品:快速、确定性、离线的包管理,建立在 npm 为您提供的基础上。任何 JS 项目都值得一看,特别是因为它很容易将其换入/换出。
EDIT (May 2019) "Bower has finally been deprecated. End of story." (h/t: @DanDascalescu, below, for pithy summary.)
编辑(2019 年 5 月)“鲍尔终于被弃用了。故事结束。” (h/t:@DanDascalescu,下面是简洁的总结。)
And, while Yarn is still active, a lot of the momentum for it shifted back to npm once it adopted some of Yarn's key features.
而且,虽然 Yarn仍然活跃,但一旦它采用了 Yarn 的一些关键特性,它的很多动力就会转移回 npm。
回答by Dan Dascalescu
2017-Oct update
2017 年 10 月更新
Bower has finally been deprecated. End of story.
Bower 终于被弃用了。故事结局。
Older answer
较旧的答案
From Mattias Petter Johansson, JavaScript developer at Spotify:
来自 Spotify 的 JavaScript 开发人员 Mattias Petter Johansson:
In almost all cases, it's more appropriate to use Browserify and npm over Bower. It is simply a better packaging solution for front-end apps than Bower is. At Spotify, we use npm to package entire web modules (html, css, js) and it works very well.
Bower brands itself as the package manager for the web. It would be awesome if this was true - a package manager that made my life better as a front-end developer would be awesome. The problem is that Bower offers no specialized tooling for the purpose. It offers NO tooling that I know of that npm doesn't, and especially none that is specifically useful for front-end developers. There is simply no benefit for a front-end developer to use Bower over npm.
We should stop using bower and consolidate around npm. Thankfully, that is what is happening:
在几乎所有情况下,使用 Browserify 和 npm 比 Bower 更合适。它只是比 Bower 更好的前端应用程序打包解决方案。在 Spotify,我们使用 npm 来打包整个 Web 模块(html、css、js),并且效果很好。
Bower 将自己打造成网络包管理器。如果这是真的,那就太棒了 - 一个让我的前端开发人员生活更美好的包管理器会很棒。问题是 Bower 没有为此提供专门的工具。它没有提供我知道 npm 没有的任何工具,尤其是没有提供对前端开发人员特别有用的工具。对于前端开发人员来说,使用 Bower 而不是 npm 没有任何好处。
我们应该停止使用 bower 并围绕 npm 进行整合。值得庆幸的是,这就是正在发生的事情:
With browserify or webpack, it becomes super-easy to concatenate all your modules into big minified files, which is awesome for performance, especially for mobile devices. Not so with Bower, which will require significantly more labor to get the same effect.
npm also offers you the ability to use multiple versions of modules simultaneously. If you have not done much application development, this might initially strike you as a bad thing, but once you've gone through a few bouts of Dependency hellyou will realize that having the ability to have multiple versions of one module is a pretty darn great feature. Note that npm includes a very handy dedupe toolthat automatically makes sure that you only use two versions of a module if you actually haveto - if two modules both canuse the same version of one module, they will. But if they can't, you have a very handy out.
使用 browserify 或 webpack,将所有模块连接成大的缩小文件变得非常容易,这对性能来说非常棒,尤其是对于移动设备。Bower 并非如此,这将需要更多的劳动力才能获得相同的效果。
npm 还使您能够同时使用多个版本的模块。如果你没有做过很多应用程序开发,这最初可能会让你觉得这是一件坏事,但是一旦你经历了几次依赖地狱,你就会意识到拥有一个模块的多个版本的能力是一件非常糟糕的事情很棒的功能。需要注意的是NPM包括一个非常方便的重复数据删除工具,可自动确保您只使用一个模块的两个版本,如果你确实有到-如果两个模块都可以使用一个模块的版本相同,他们会的。但如果他们不能,你有一个非常方便的。
(Note that Webpackand rollupare widely regarded to be better than Browserify as of Aug 2016.)
回答by Sagivf
Bower maintains a single version of modules, it only tries to help you select the correct/best one for you.
Bower 维护单一版本的模块,它只会尝试帮助您为您选择正确/最佳的模块。
NPM is better for node modules because there is a module system and you're working locally. Bower is good for the browser because currently there is only the global scope, and you want to be very selective about the version you work with.
NPM 更适合节点模块,因为有一个模块系统并且您在本地工作。Bower 对浏览器很有用,因为目前只有全局范围,并且您希望对使用的版本非常有选择性。
回答by Nick Heiner
My team moved away from Bower and migrated to npm because:
我的团队离开 Bower 并迁移到 npm,因为:
- Programmatic usage was painful
- Bower's interface kept changing
- Some features, like the url shorthand, are entirely broken
- Using both Bower and npm in the same project is painful
- Keeping bower.json version field in sync with git tags is painful
- Source control != package management
- CommonJS support is not straightforward
- 程序化使用很痛苦
- Bower 的界面不断变化
- 某些功能(例如 url 速记)完全损坏
- 在同一个项目中同时使用 Bower 和 npm 是痛苦的
- 保持 bower.json 版本字段与 git 标签同步是痛苦的
- 源代码控制 != 包管理
- CommonJS 支持并不简单
For more details, see "Why my team uses npm instead of bower".
有关更多详细信息,请参阅“为什么我的团队使用 npm 而不是 bower”。
回答by Henry Neo
Found this useful explanation from http://ng-learn.org/2013/11/Bower-vs-npm/
从http://ng-learn.org/2013/11/Bower-vs-npm/找到这个有用的解释
On one hand npm was created to install modules used in a node.js environment, or development tools built using node.js such Karma, lint, minifiers and so on. npm can install modules locally in a project ( by default in node_modules ) or globally to be used by multiple projects. In large projects the way to specify dependencies is by creating a file called package.json which contains a list of dependencies. That list is recognized by npm when you run npm install, which then downloads and installs them for you.
On the other hand bower was created to manage your frontend dependencies. Libraries like jQuery, AngularJS, underscore, etc. Similar to npm it has a file in which you can specify a list of dependencies called bower.json. In this case your frontend dependencies are installed by running bower install which by default installs them in a folder called bower_components.
As you can see, although they perform a similar task they are targeted to a very different set of libraries.
一方面,创建 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 的文件夹中。
如您所见,尽管它们执行类似的任务,但它们针对的是一组非常不同的库。
回答by jessopher
For many people working with node.js, a major benefit of bower is for managing dependencies that are not javascript at all. If they are working with languages that compile to javascript, npm can be used to manage some of their dependencies. however, not all their dependencies are going to be node.js modules. Some of those that compile to javascript may have weird source language specific mangling that makes passing them around compiled to javascript an inelegant option when users are expecting source code.
对于许多使用 node.js 的人来说,bower 的一个主要好处是管理根本不是 javascript 的依赖项。如果他们使用编译为 javascript 的语言,可以使用 npm 来管理他们的一些依赖项。然而,并不是所有的依赖都是 node.js 模块。一些编译为 javascript 的代码可能有奇怪的源语言特定的修改,这使得当用户期待源代码时,将它们编译为 javascript 是一个不雅的选择。
Not everything in an npm package needs to be user-facing javascript, but for npm library packages, at least some of it should be.
并非 npm 包中的所有内容都需要面向用户的 javascript,但对于 npm 库包,至少应该有一些。