What is the difference between Bower and npm?

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.


npm is most commonly used for managing Node.js modules, but it works for the front-end too when combined with Browserify and/or $ npm dedupe .

Bower is created solely for the front-end and is optimized with that in mind. The biggest difference is that npm does nested dependency tree (size heavy) 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 is really great on the server where you don't have to care much about space and latency. It lets you not have to care about dependency conflicts as all your dependencies use eg their own version of Underscore. This obviously doesn't work that well on the front-end. Imagine a site having to download three copies of jQuery.

The reason many projects use both is that they use Bower for front-end packages and npm for developer tools like Yeoman, Grunt, Gulp, JSHint, CoffeeScript, etc.

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


Resources

  • Nested Dependencies - Insight into why node_modules works the way it does

  • 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:

    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:

    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:

    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 (eg runtime, where you avoid duplication), and use npm for other stuff, like testing, building, optimizing, checking, etc. (eg 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


    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.

    链接地址: http://www.djcxy.com/p/2978.html

    上一篇: 将原始GitHub存储库中的新更新引入分叉的GitHub存储库

    下一篇: Bower和npm有何区别?