bendrucker / ama

Ask me questions about building web applications
MIT License
6 stars 1 forks source link

Using Bower vs. NPM #1

Closed kenkopelson closed 9 years ago

kenkopelson commented 9 years ago

Hi Ben :)

Regarding the article you linked me to:

http://blog.npmjs.org/post/101775448305/npm-and-front-end-packaging

I read the entire article plus the comments at the end. The node team recognises that NPM is NOT the place yet to store packages for the front-end, for all the reasons stated in the article. While they do aspire to that someday, they admit that NPM is not ready for that, and they are are still a bit "iffy" about when they plan to do. In the comments, there was some agreement that the "N" is NPM stands for Node, and that using it to manage front-end packages, which have different requirements, seems weird.

Also, notice how their stats show that the second most popular thing that people download with NPM is...Bower! This is because people first get NPM, then they use it to get Bower, which makes sense.

So, until NPM is able to fully handle the 4 problems mentioned in the article, I'm afraid that "NPM = Node" is not really wrong presently. It may become wrong in the future, which would be nice!

kenkopelson commented 9 years ago

Also, I keep having this nagging issue with Font-Awesome that seems quite silly. Because they renamed their package from "font-awesome" to "Font-Awesome" as part of upgrading from 3.1.x to 4.1.x they have caused a lot of problem with those of us developing on OSX. As you likely know, OSX is a case-insensitive/case-preserving OS (default), which is not the same as Unix/Linux. To the OS, these both look like the same file, and so you can't have both present in the same folder. So, depending on which one gets pulled last, that is the one that wins, and since they are major release variations, they are not compatible.

It seems that people who rename their package strictly by changing the case of letters are totally ignoring the fact that most of the world runs with case-insensitive environments. Mac OSX is a great environment for development, and I have nothing bad to say about it. Really, using capitals in a package name is breaking the standard convention used by everyone else on the planet.

Your thoughts on how I could fix this problem (short of reformatting my hard disk to be case-sensitive)?

bendrucker commented 9 years ago

First, I'll add what I mentioned via email: I've completely eliminated Bower from all of my applications. I'll split the reasons into three sections:

  1. Reasons why Bower is badR
  2. Reasons why npm is good
  3. Caveats

npm was being pretty humble and I'm willing to fire more direct shots at Bower. Let's keep this convo going because I'd like to flesh out ideas to write into a blog post.

Bower is bad and it should feel bad

Registry is just git

Bower basically just maps a package name to a git endpoint. It fetches all the tags and then allows you to select versions using semver operators by matching against tags. In theory, it sounds like a cool idea. But in practice, a ton of projects want to run a build step and publish that build artifact in their releases. Bower basically makes this impossible because there's no concept of publishing code to the registry.

I had to write browserify-bower-release to hack my way around this limitation. Committing a build to master is unacceptable. I have at least one recent example of another package maintainer (Petka, creator of Bluebird https://github.com/petkaantonov/bluebird/issues/427) running into this issue.

This isn't a trivial concern — the best JavaScript developers these days are pretty much in universal agreement that small modules that solve a single problem are the way forward. More on this later.

No lifecycle hooks

The alternative solution to publishing builds to a registry that stores code is installing all the dependencies and building on a user's machine when they install. Gross, but it would be a low-friction option for library maintainers. We could just npm install && npm run build since anyone who has bower has npm. It would be slow, but it would work.

Except bower has no hooks. You can define hooks in .bowerrc for your project, but packages don't get their own hooks.

Unclear package schema

Bower's aversion to conventions means things get weird. You can set main, but that really doesn't mean anything unless you're using a bower-aware tool that expects to find a bower.json with a main property. When the convention is optional, it's worthless. The comparable case in npm is also main and it determines what you get when you require('package').

I happen to always use ./src as main which resolves to ./src/index.js. Others use ./lib. Or ./. Etc. Those are style choices because the package system deals with exposing a consistent external API that hides internal implementation details from users.

Because bower wants to be all front end things to all people, you have to deal with the possibility/certainly that packages will misbehave and management becomes another chore for you.

Why npm

dedupe is automatic

I've watched people try to use bower. Every single install is a mess of complaints about version mismatches. It's not Bower's fault that people don't read and understand their dependencies. But it's also not necessary to expose that kind of functionality so blatantly to users. npm dedupe works just fine, assuming you're using well behaved packages. Again, more on this later.

In general, npm is just a more full featured package management tool, whereas bower is trying to do too little.

browserify

Part of what complicates things in this discussion is that npm is ideally suited for modern application development, where bower is going to be better suited to designing applications like it's 2005. If you want to concatenate all your scripts, you have to work against npm. I write 100% of my JavaScript in CommonJS and would never go back.

Browserify is an amazing tool with a fantastic ecosystem to go along with it. Modern applications are just too complex for script concatenation to work. There is no problem I'm aware of with JS targeting the browser that npm and browserify cannot solve together.

Caveats

developers, developers

A lot of my love for the npm / node / browserify way of doing things comes from a package maintainer angle. I'm proud of the stuff I publish and the npm way of small modules, deeply nested makes me more productive and effective.

When it comes to Angular, I'm sort of a rarity in thinking this way. I believe I may be the largest individual publisher of angular packages that doesn't work for Google at this point. I've really been astounded by the amount of garbage with hundreds of stars written for Angular. To pick a particular example relevant to you, angular-credit-cards is a properly written package. It does only one thing (tie together directives to an external API). It has 100% test coverage. And most importantly, it delegates all the creditcard parsing and validation to creditcards, itself a totally independent package that is also well written.

Take something more complex like convex. qs is a critical and large dependency, as is uuid. Forcing the end user to insert script tags is opening up an opportunity for mistakes.

Good developers take advantage of the ability to compose small modules into great things. npm is awesome for that. Bower is terrible for that. I don't think it's unfair to say that Bower encourages bad code and exerts a negative influence on the browser JS ecosystem at this point in history.

frontend !== code

This is really the only point I'll concede, at least partially. Bower does more than just JS, and right now npm has no special advantage for something like bootstrap. On the other hand, it doesn't have any particular disadvantage either. As long as your packages are well behaved and choose the right semver range, you should be fine. Use peerDependencies and then just import that css from node_modules/bootstrap/style_file.css or whatever it's named.

I don't use third party CSS or icon packs, so I can't really speak to whether they're publishing to npm. If not you're stuck with bower there.

bendrucker commented 9 years ago

re: Font Awesome, that's crazy that they'd choose a title case name. No sane reason to do that. I'm on OS X so that'd bite me too. Open a fresh issue though. I might have an idea on how to fix it even if they refuse to name their package properly.

kenkopelson commented 9 years ago

Thanks Ben for that excellent post on Bower vs. NPM! Well written and compelling. While I agree with the overall approach, for me, I have all the back-end to my site under the /app subdirectory, and all the front-end under /public. Then I have files that apply to both in the root, such as cluster.js, server.js, package.json, etc. All of my front-end code is in one place, and it's all managed by Bower. With your concession about "other front-end stuff", you suggested that I would just have to be stuck with Bower for things like CSS, fonts, images, but then could use NPM for the JS.

I've just now taken a look at Browserify and it looks fantastic! When we first started talking about this I hadn't yet taken time to really look at that great tool in depth. Now that I fully understand what it's doing, I can see more of the reasons for your arguments. I actually wrote some code that could be used in Angular or Node, and it was tricky to get it working, and kind of ugly. Also, I've tried to concat all my JS files for the browser (using the antiquated methods) and couldn't get it work. Sounds like Browserify is the answer! I'll let you know how I get on with this.

Cheers!

bendrucker commented 9 years ago

Glad to be helpful. Browserify and the small modules philosophy aren't directly connected but in practice they definitely overlap. I separate front end apps completely from server code.