Skip to content

1.1.1 breaks browserify #2997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rthewhite opened this issue Feb 14, 2014 · 67 comments
Closed

1.1.1 breaks browserify #2997

rthewhite opened this issue Feb 14, 2014 · 67 comments

Comments

@rthewhite
Copy link

Hello,

Version 1.1.1 breaks the browserify build of backbone. It's trying to require jQuery although backbone itself doesn't have a dependency on it.

I know there is a try, catch around it but this doesn't work with browserify it will just try to resolve the require which fails and causes the build to fail.

@akre54
Copy link
Collaborator

akre54 commented Feb 14, 2014

Hrrm. That's no good. Any suggestions? Pinging @substack...

@rthewhite
Copy link
Author

Let me clear something. Probably a lot of developers that are using backbone and browserify will use it together with jQuery and if they are smart they will now use jQuery from NPM since it's available there. Then the problem is resolved because they already got jQuery in their node_modules folder.

I'm currently working in the project where jQuery wasn't available when we started so we shimmed it. That's why i stumbled on this issue.

Basically everyone that wants to use Backbone together with Browserify without jQuery or that uses a jQuery shim probably has issues now. The workaround is to include jQuery from NPM. But i don't think it's really nice to have a hard dependency to get it working while Backbone actually doesn't really have that dependency on jQuery.

@tgriesser
Copy link
Collaborator

I hit this issue too, the problem is that jquery pre-2.0 from npm isn't really the jquery you're looking for, but one that is intended for use on the server, so you have to shim it.

Not sure what the best solution is here, IIRC setting the jquery path in the browser paths didn't fix it.

@rthewhite
Copy link
Author

tgriesser, that's not a problem anymore. Since 2.1 and 1.11 jQuery is now officially available from NPM so if you don't need a version before those 2 than you can use those.

@akre54
Copy link
Collaborator

akre54 commented Feb 14, 2014

We run browserify with the debowerify transform, so I've never run into this. I assume there should be some way to stub out jquery within Browserify...

@tgriesser
Copy link
Collaborator

Wow, I was looking for a transform like that, I have no idea how I missed it!

@iraytje ah yeah that must've been the problem - I think I needed ~1.8 for some plugin compatibility reason

@jashkenas
Copy link
Owner

So is there a change we should make here? It seems like attempting to load jquery, if available, within Node, is likely the right thing to do.

Should we instead take the position that if you're running Backbone server-side, then you're never looking to use the views, and only want the models and collections?

@akre54
Copy link
Collaborator

akre54 commented Feb 14, 2014

Nah loading jquery server-side is definitely a valid use case. We should have a wiki page (or I'll write a blog post) with how to shim when it's not desirable (no jquery in the browser is whats at issue here, which seems like a small edge case).

@rthewhite
Copy link
Author

I think it's a shame to have Backbone in NPM which doesn't work with browserify because it's requiring a module ( even if it's conditionally ) that is not a dependency of Backbone itself.

Why even attempt to load jQuery from within Backbone? Even server side, if you want to use them together, you should load jQuery yourself and assign it to Backbone like it's always been.

That will fix the issue for everyone and doesn't require a blog post about using backbone with browserify and how to shim it.

@jashkenas
Copy link
Owner

Backbone in npm is designed to work with Node. That's the natural order of things. If it also happens to work with browserify, then that's a bonus.

@tgriesser
Copy link
Collaborator

Why even attempt to load jQuery from within Backbone? Even server side, if you want to use them together, you should load jQuery yourself and assign it to Backbone like it's always been.

I tend to agree with this though.

@jashkenas
Copy link
Owner

Fair enough, and that's how it used to be. Where did the change come from that introduced the try/catch attempt to load jQuery when in Node?

@tgriesser
Copy link
Collaborator

Somewhere around these: #2862 #2857

@akre54
Copy link
Collaborator

akre54 commented Feb 14, 2014

The goal of #2862 was to make the common case of server-side node or browser-based commonjs (using jquery) work without hassle.

I'm not opposed to reverting, but we should add a note to the docs / changelog for the common case:

// commonjs
var Backbone = require('backbone');
Backbone.$ = require('jquery');

// amd
define(['backbone', 'jquery'], function(Backbone, $) {
  Backbone.$ = $;
});

@tgriesser
Copy link
Collaborator

Shouldn't need the note for amd though, since that's taken care of in the earlier block of code.

@wookiehangover
Copy link
Collaborator

I'm running into this too -- seems like there are also issue with AMD projects that use bower and requirejs getting automatically upgraded to 1.1.1, seems like there are issues with shimming + plugins.

Thinking that 1.1.1 should have really been 1.2 since its breaking things for lots of people :(

The real culprit is that npm install --save backbone and bower install --save backbone both write "~1.1.0" to their configs, but my first notice about things not working was CI blowing up across a few projects.

@tbranyen
Copy link
Collaborator

I was recently pointed to the browser configuration within package.json that may help with this:

https://github.com/substack/node-browserify#browser-field

@ghost
Copy link

ghost commented Feb 14, 2014

Why doesn't backbone just include:

"jquery": "~2.1.0"

in its package.json dependencies field? I have no idea why a module would ever require() a package without putting that package into the dependencies field. This seems really weird.

@braddunbar
Copy link
Collaborator

Or perhaps "jquery": ">=1.11.0"?

@tbranyen
Copy link
Collaborator

@substack for historical reasons it makes sense since the old jquery package was not something i'd ever want downloaded in my project.

@akre54
Copy link
Collaborator

akre54 commented Feb 14, 2014

Because Backbone itself doesn't depend on jQuery (unlike, say, Underscore). In node, if the package doesn't exist, the require throws.

@jashkenas
Copy link
Owner

Why doesn't backbone just include:
"jquery": "~2.1.0"
in its package.json dependencies field?

... because when you load Backbone in Node — you probably don't want jQuery as a dependency. But a few folks might.

@ghost
Copy link

ghost commented Feb 14, 2014

I am not getting something about this thread at all. My naive understanding of how dependencies work:

If you require() a package, then it is a dependency. Dependencies go in the package.json
dependencies field.

But here in this thread, people are telling me that despite require('jquery') being present in the code, jquery is NOT a dependency? If jquery is not a dependency of backbone:

  • What is require('jquery') doing in the code? Take it out!

-- OR --

  • jquery is actually a dependency of backbone and belongs in the package.json dependencies field.

If there is some weird third-case middleground shenanigans going on, take it out. Hacks like that don't belong.

@ghost
Copy link

ghost commented Feb 14, 2014

Addendum: like @tbranyen already pointed out, if the problem is that you want something different to happen in node vs the browser, you can use something like the browser field to specify a different entrypoint or per-file overrides.

@akre54
Copy link
Collaborator

akre54 commented Feb 14, 2014

@substack jQuery is an optional, or "light", dependency of Backbone. You can load and use Backbone just fine without jQuery present first. Backbone.$, the reference to jQuery, can be lazily set anytime.

@Raynos
Copy link

Raynos commented Feb 14, 2014

As mentioned by @akre54 you should add

// browserify
var Backbone = require('backbone');
Backbone.$ = require('jquery');

to the docs somewhere.

@island205
Copy link

I came across the issue. Although the conclusion has been made, I also think it is a bug need fix. Because lots of people come across it. it confuse people, Backone really depends on $ whatever jquery or zepto. we can't assume that $ is not need in node.js, in commonjs or browserify, and this hypothesis is wrong, otherwise there are not so many people came across the problem.

There are two way to solve this problem:

  1. fix selfly : add jquery or zepto to package.json
  2. export interface surely and well docs: Backone.set$ to set the $

I think the code following also has the problem:

define(['underscore', 'jquery', 'exports'], factory)

you can see jquery here, but not in bower.json. Again, using jquery in amd, and why no using jquery in commonjs.

@dgbeck
Copy link

dgbeck commented Aug 16, 2014

Yeah this issue is continuing to cause friction. The backbone.$ fix does not solve the problem as it is non-obvious, awkward, and can easily lead to multiple copies of jquery being loaded since jquery does generally need to be an explicit dependency of view classes packaged as their own modules.

The reason cited above for not simply including query in package.json is:

... because when you load Backbone in Node — you probably don't want jQuery as a dependency. But a few folks might.

@jashkenas what is the problem with jquery being an unused dependency in node? Who cares? It takes up virtually no disk space and no time to load, which it happens only once when the thread starts. Let just bite the bullet and go back to what is simple and practical.

@akre54
Copy link
Collaborator

akre54 commented Nov 4, 2014

Yeah in retrospect I wish I'd stood my ground on this one. I'd like to revert f1479e6 and add a note to the wiki page about it.

@jamesplease
Copy link
Contributor

Yeah in retrospect I wish I'd stood my ground on this one. I'd like to revert f1479e6 and add a note to the wiki page about it.

This is a conversation worth having, I think. The current set up continues to be problematic for folks trying to load libraries that build on top of Backbone within the browser. I think we can do better!

@akre54
Copy link
Collaborator

akre54 commented Dec 18, 2014

Agreed. I think it's confusing in commonjs mode that we load Underscore but not jQuery, while in AMD and global mode we load both for you.

Enough client side code these days uses commonjs that I think it's time we reëxamine this.

@samccone
Copy link

not to add more noise to this thread, but based on the volume of issues and questions raised in marionette land directly related to this change, reverting this commit would save many people time, and make their lives much easier. 👍 @akre54

@rthewhite
Copy link
Author

Agreed. I think it's confusing in commonjs mode that we load Underscore but not jQuery, while in AMD and global mode we load both for you.

The big difference here is that Backbone officially has a dependency on Underscore and it's included in the package.json. jQuery isn't, by adding the optional require in the code. Everybody that uses Browserify is obligated to expose at least some module for the jQuery dependency otherwise their build won't even work.

@jashkenas
Copy link
Owner

if you guys want to change this, feel free to open a new pull request — with the desired change made, and a full description of the rationale for it ... and explanation of how it's going to work and play out in different environments.

@symmetriq
Copy link

I've had a PR open for this for quite some time: #3038

@jashkenas
Copy link
Owner

No. That PR does not try to require jQuery, and it does not fully describe and explain how it's going to work in different environments.

If you want to change this, let's put in the elbow grease to really explain it to an idiot (like me), who's going to have to be able to push the merge button with something resembling confidence.

@akre54
Copy link
Collaborator

akre54 commented Dec 19, 2014

My laptop is at the genius bar the next few days, so if someone doesn't
open a PR before then I'll add my own.

Main gist is we want the common case of loading jQuery to work without
issue.

For folks who don't need jquery, they should tell their build tool to
ignore the require. In node this is done by throwing an error (which we a
catch and ignore). For browserify / webpack it's through a config option.

The Backbone.$ variable is still available for ender, Zepto, etc.

@island205
Copy link

@akre54 +1

@braddunbar
Copy link
Collaborator

For browserify / webpack it's through a config option.

I'm not famiar with this option. What would it look like?

@dgbeck
Copy link

dgbeck commented Dec 19, 2014

Can somebody please help me understand why jquery can not go in package.json like all the other dependencies? No try / catch, no surprises, no weirdness.

On the server side, it takes up an insignificant amount of space and time to load. In the browser, if somebody is using a DOM library other than jquery, then the onus can be on that person to swap it out for their library of choice. With browserify, this can be done easily with browserify-shim. I'm not sure about webpack, but there must be a way. I'd like to put together a PR for this simple case w/ examples on how to handle non-jquery-dom-libs but is there some con I'm not seeing that should be considered?

@braddunbar
Copy link
Collaborator

Can somebody please help me understand why jquery can not go in package.json like all the other dependencies?

Good question! It's obviously regarding people who don't use jQuery, but I am curious about this. Is it just because aliasing zepto (or similar) as jquery is distasteful or do things really break? Re-reading this thread, I didn't see any mention of actual breakage if it's just included in package.json.

That said, I've been using Backbone.$ = require('jquery'); in my router/app for some time and, while it's a bit odd, I haven't had any problems with it.

@jamesplease
Copy link
Contributor

Can somebody please help me understand why jquery can not go in package.json like all the other dependencies?

I've been asking myself this question for some time. I know of no other issues for folks on the server other than the two minor inconveniences you mentioned, so I'm not sure why the current set-up is favoring that use case.

Although @jashkenas has described this as the use-case, I think there's something more problematic than this when it comes to the client. More on this in a sec...

That said, I've been using Backbone.$ = require('jquery'); in my router/app for some time and, while it's a bit odd, I haven't had any problems with it.

If you're just using Backbone, then it's no problem. The issue comes in when you load a library, like Marionette, that depends on Backbone having $ defined. For Marionette to work with Backbone in, say, a webpack environment, you have to force webpack to inject the dep in the configuration. This is difficult for folks who are trying to get set up who may not be experts at module bundlers.

For browserify / webpack it's through a config option.

I'm curious to see this, too. I'm familiar with the alias option, which would easily let people swap jQuery for, say, Zepto, but I admit I'm not sure how one would configure Backbone to ignore jQuery if we change this set up to include jquery in the package.json and add the require line. This is that problem I mentioned earlier on in this post.

@braddunbar
Copy link
Collaborator

Also, what if you want Backbone to use Zepto but still use jQuery in other areas? Can aliasing work in that case?

@akre54
Copy link
Collaborator

akre54 commented Dec 19, 2014

The issue comes in when you load a library, like Marionette, that depends on Backbone having $ defined.

I always just set up Backbone.$ before loading Marionette / Chaplin / Thorax. Not ideal, but certainly not tedious:

require('Backbone').$ = require('jquery');
var Marionette = require('Marionette');

@braddunbar
Copy link
Collaborator

@akre54 Exactly! Also, in plugins that use jQuery directly it seems that one should rely on it directly instead of using Backbone.$. That way you can upgrade them separately without fear of breakage. At least, it's what I've done in the past.

@akre54
Copy link
Collaborator

akre54 commented Dec 19, 2014

Also, in plugins that use jQuery directly it seems that one should rely on it directly instead of using Backbone.$. That way you can upgrade them separately without fear of breakage.

I disagree on this. Marionette should be using the same jQuery as Backbone and the same jQuery as your app. It becomes an absolute mess when your view's $el property has a different $.fn than the rest of your app (no plugins, etc). Metaframeworks should always use the Backbone.$ variable instead of trying to require jQuery itself.

@braddunbar
Copy link
Collaborator

Fair enough! 😃

@akre54
Copy link
Collaborator

akre54 commented Dec 19, 2014

I'm not famiar with this option. What would it look like?

$ browserify app.js --exclude jquery

For Webpack, it'll throw a runtime error. Just like in node.

{
    plugins: [
        new webpack.IgnorePlugin(/^jquery$/)
    ]
}

tillberg pushed a commit to tillberg/tbone that referenced this issue Apr 15, 2015
This results in hard dependencies a la jashkenas/backbone#2997
but there doesn't appear to be a trivial way out of that.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests