乐闻世界logo
搜索文章和话题

What is the difference between bower and npm

5 个月前提问
3 个月前修改
浏览次数31

6个答案

1
2
3
4
5
6

Bower和npm在功能上有着明显的区别,主要体现在它们各自的侧重点和使用场景上。以下是主要的区别:

  1. 侧重点不同

    • Bower:Bower是一个前端包管理工具,专注于HTML、CSS、JavaScript等前端技术的库和框架的管理。Bower的特点是可以解决前端库的依赖问题,例如,当你需要引入一个前端库时,Bower可以自动下载该库所依赖的其他库。
    • npm:npm(Node Package Manager)起初是Node.js的包管理工具,用于管理Node.js模块。然而,随着前端工具链的发展,npm也被广泛用于前端项目中,它可以用来安装和管理项目依赖的库和工具,如React、Angular或Webpack等。
  2. 项目结构

    • Bower:往往会将依赖安装到项目的bower_components目录下。
    • npm:会将依赖放入node_modules目录。
  3. 包内容

    • Bower:通常包含的是编译后的代码,即最终将在浏览器中运行的代码。
    • npm:可能包含源码、编译后的代码,也可能包含命令行工具等。
  4. 依赖管理

    • Bower:使用bower.json文件来管理项目的依赖关系。
    • npm:使用package.json文件来管理依赖,并且在npm v5之后,默认生成一个package-lock.json或在Yarn中的yarn.lock来锁定依赖版本,确保不同环境下安装的依赖版本一致。
  5. 命令行接口

    • Bower:提供了一系列简单的命令来安装和管理前端库,例如bower installbower update等。
    • npm:提供了更全面的命令行工具,不仅能安装和管理包,还能运行脚本,发布模块等,如npm installnpm updatenpm run等。
  6. 社区和生态

    • Bower:在早期前端开发中被广泛使用,但随着前端工具链的发展和npm的成熟,Bower的使用已经大幅减少。Bower自2017年起不再推荐使用,并且建议用户迁移到npm上。
    • npm:有着庞大的社区支持和丰富的模块生态。随着Node.js的流行,npm成为了JavaScript世界中最大的模块仓库。

举个例子,假设你在开发一个Web应用,需要引入jQuery和Bootstrap,使用Bower的话,你只需要运行bower install jquery bootstrap,Bower会将这两个库及其依赖的其他库(如jQuery可能被Bootstrap所依赖)下载到bower_components目录下。然而,随着工具如Webpack和npm脚本的流行,你现在更可能使用npm来管理这些依赖,通过npm install jquery bootstrap命令来安装,并通过Webpack这样的模块打包工具来组织这些库和你的应用代码。

总结来说,Bower和npm在设计上针对不同的问题和应用场景。随着前端工具链的不断发展,npm已经成为前后端通用的依赖管理工具,而Bower则逐渐淡出了主流的开发实践。

2024年6月29日 12:07 回复

All package managers have many downsides. You just have to pick which you can live with.

History

npm started 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 Browserify or webpack.

Bower is created solely for the front-end and is optimized with that in mind.

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).

Bower has a much smaller amount of packages.

Handling of styles etc

Bower includes styles etc.

npm is focused on JavaScript. Styles are either downloaded separately or required by something like npm-sass or 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).

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 be flat by default (saving space) and only nest where needed, e.g., if two dependencies need their own version of Underscore.

Some projects use both: they use Bower for front-end packages and npm for developer tools like Yeoman, Grunt, Gulp, JSHint, CoffeeScript, etc.


Resources

2024年6月29日 12:07 回复

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.

On the npm FAQ: (archive.org link from 6 Sep 2015)

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.

On Bower homepage:

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.

In short, npm aims for stability. Bower aims for minimal resource load. If you draw out the dependency structure, you will see this:

npm:

shell
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!

Bower:

shell
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?

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 conflict because 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.

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).

Update for 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).

  • [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)

For more information, I suggest reading the docs of npm 3

2024年6月29日 12:07 回复

TL;DR: The biggest difference in everyday use isn't nested dependencies... it's the difference between modules and globals.

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.)

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.

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.

The Bower Approach: Global Resources, Like <script> Tags

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.

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.

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.

The npm Approach: Common JS Modules, Explicit Dependency Injection

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.

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 encapsulated behind 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 can happen, 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 assigning this.variable, not realizing that this is actually window 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.

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:

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.

At the end of a file, you export whatever you want to share with the world, like this:

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.

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 overview of those as well.

More about patterns for working with modules in this deck.


EDIT (Feb 2017): Facebook's Yarn is 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.


EDIT (May 2019) "Bower has finally been deprecated. End of story." (h/t: @DanDascalescu, below, for pithy summary.)

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.

2024年6月29日 12:07 回复

2017-Oct update

Bower has finally been deprecated. End of story.

Older answer

From Mattias Petter Johansson, JavaScript developer at Spotify:

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:

Module counts - bower vs. 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 hell you 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 tool that automatically makes sure that you only use two versions of a module if you actually have to - if two modules both can use the same version of one module, they will. But if they can't, you have a very handy out.

(Note that Webpack and rollup are widely regarded to be better than Browserify as of Aug 2016.)

2024年6月29日 12:07 回复

Bower maintains a single version of modules, it only tries to help you select the correct/best one for you.

Javascript dependency management : npm vs bower vs volo?

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.

2024年6月29日 12:07 回复

你的答案