-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Remove jQuery dependency. #2865
Conversation
As discussed in gh-2859, taken from [Exoskeleton](http://exosjs.com). This change makes jQuery dependency 100% optional. If jQuery is included, everything will still work as-is. New stuff: * `View#delegate` and `View#undelegate` for native event delegation. * `utils.matchesSelector` and `utils.ajax` for fast and convenient selector matching / XHR shortcut * `Backbone.Deferred` for custom deferred libraries (I think this is a big deal since Chrome now has native promises) Native DOM view tests are in test/no-jq.html and test/view-no-jq.js.
There are not much comments around, but let's see whether this may be merged at first. cc @akre54 |
var tag = document.createElement('div'); | ||
var name, method; | ||
// Detect the right suffix. | ||
['matches', 'webkit' + sfx, 'moz' + sfx, 'ms' + sfx].some(function(item) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IE8 doesn't support Array#some. Use _.some instead for fallback
How would people feel if we used That is, instead of: if (Backbone.$) {
Backbone.$(window).on('hashchange', this.checkUrl);
} else {
window.addEventListener('hashchange', this.checkUrl, false);
} ...we'd just use: if (window.addEventListener) {
window.addEventListener('hashchange', this.checkUrl, false);
} else {
window.attachEvent('onhashchange', this.checkUrl);
} |
var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); | ||
this.setElement($el, false); | ||
} else { | ||
var el = _.extend(document.createElement(_.result(this, 'tagName')), attrs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there anything that using $el.attr(attrs)
gives us that _.extend(this.el, attrs)
doesn't? Looking in the source, I'm not seeing much advantage of going the jq route.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually something related to prop
vs attr
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct ajax example docs
I've made a comment on the ticket. In general I don't like this PR at all, there should be much simpler implementation that's compatible and much less ambitious. |
Fix tests
@akre54 it's cool probably, yup |
Theres a lot I like about the ideas in this pull. But at the moment it's just too confusing and the potential for frustrating upgraders is just too high. Upgrading to this hypothetical version of BB should be a no-brainer; there should be clear instructions for how to use Backbone without the jQuery dependency, and for everyone else it breaks nothing. Normally I'd vote for offloading this stuff to a plugin that overwrites a few of the smaller methods in Backbone.View.prototype, but jQuery is just too baked into View/History at the moment. You basically have to overwrite your own View as @wyuenho did for Backgrid to get the opt-out. Here are my suggestions:
This pull differs from Backbone's philosophy in some respects (Backbone tends to not live on the bleeding edge wrt. vendor-prefixed features like matches) but nails it in others (modularity, minimum 3rd-party dependence, and natives -- Backbone already includes fallbacks for non-pushState browsers, for example). I'd rather the native approach gets baked into the Backbone API and not run Exoskeleton as YAJPS (Yet Another Jashkenas Project Spinoff) because of its core usefulness, but I also agree with keeping the project lightweight. What would it take to convince you, @wyuenho? |
ping @jashkenas |
That got a big laugh. I agree pretty much completely here with @akre54's sentiments. The additional logic branches are very displeasing, and the chances of backwards-compat destruction seem way too high. But I still think this is quite promising. How about this approach? Instead of the jQuery checks in this PR, remove all jQuery references from within the Backbone source. In their place, place Backbone.ajax, and Backbone.dom-style function calls, which will serve as the plug-in point going forwards. Then provide a tiny module that implements Backbone.ajax and Backbone.domWhatever via jQuery — this is the module that ships with the core backbone.js file, and leaves compatibility the same. Then you're free to implement a Backbone.exoskeleton (or whatever) plugin that provides the same small set of functions, and does so natively, having identified the core external API, and separated it out already in Backbone proper. This alternative dependency wouldn't ship in the main Backbone.js file, but could perhaps be provided right alongside it, and linked to at the top of the docs. Sound reasonable? |
Let me give a thought to what this API would look like and I'll open a pull in the next couple days if I can think of a minimally hairy way to do it. I like the idea of decoupling jQuery but leaving it as the default. |
Interesting idea. So, there should be calls to:
? Should native and very short implementations of |
Also, what about |
@jashkenas 's suggestion sounds good, but I worry that this all or nothing approach may not work in practice. As I've said before, in a realistic large app, you'll very likely be using a jQuery plugin and you'll inevitably bring in jQuery as a dependency anyway. An all-native backbone core will keep backbone light and fast on mobile, but I'd really need some kind of opt out mechanism in the View such that I can avoid jQuery in hot code on desktop. How about introducing a BaseView or NativeView or whatever, and make View extend from it? View can just override in BaseView to get backward-compat. All of these still sounds like a lot of code changes, and I fear the final product will feel like it's polyfilling Backbone. |
One of Backbone's best features is it's staunch commitment to it's goals and abstraction level. It is a library of data-structuring primitives. It is not a DOM library, and it is not a low level utility library. jQuery's performance or non-performance, while relevant, is orthogonal to Backbone's goals and means for achieving them. If the state of jQuery is not to our liking we should attempt to change it or create our own, separate, DOM abstraction library rather than blur the focus of this project. jQuery's API is a great choice for abstraction because, love it or hate it, it's the most recognized javascript API in existence. In fact, my own familiarity with it is a big reason I took to Backbone so easily. Creating our own API for reasons of performance is, in my opinion, a recipe for confusion. It's the same reason we don't define a small subset of Underscore to ship with Backbone, despite the fact that Backbone does not use all of Underscore's API. The API is already used very minimally (I count less than 7 distinct usages) and defining |
So? What's up with this? @jashkenas |
You tell me ;) How's your |
If views didn't use |
I have moved So, from my production experience, i'm against
|
So I guess you won't merge this one? @jashkenas |
Yes, he won't merge 💯 |
@prust Yes but the if blocks are detecting the existence of a Backbone.$ in order to decide whether to use util or My suggestion would be to have a View constructor flag that lets me switch on or off native/jQuery instead of having to override a prototype. |
@wyuenho with var jqUtils = Backbone.utils;
Backbone.utils = require('native-utils');
var myView = new FastView;
Backbone.Utils = jqUtils; |
@akre54 that's even worse than @prust 's suggestion. I can override If everyone is against having an extra flag, I'd take @prust 's |
@wyuenho what is the problem with simply checking for |
Because it's all or nothing. I can have 3 views A, B, and C, where A and B will depend on jQuery for compatibility or jQuery plugin reasons (I suppose that's how most people use Backbone anyway), but I just want C to not use jQuery at all because it's the hot zone. Does this make sense? |
The only reason The branching just needs 1 more level of granularity. That's it. |
How exactly? Can you provide any example plugins / behaviour of this sort?
|
I have dozens of views at work that all just call jquery plugins from render like this: this.$("selector").plugin(); Or this.$el.plugin(); I'd rather not to have to change all of them just so I can have 1 view that doesn't use jQuery. Aren't all existing apps suppose to be like this? |
OK in this case here's my proposal:
If people want to go fully no-jquery, they just don't include jQuery and everything will work by default. If people want to use $ in some views, they include jQuery, set How does that sound? |
Perfect :) On Monday, December 16, 2013, Paul Miller wrote:
|
@wyuenho 1. added to this pull request. 2. added and released new Exoskeleton with |
Thank you! Let me test this out... |
As discussed in gh-2859, taken from Exoskeleton.
This change makes jQuery dependency 100% optional. If jQuery is included, everything will still work as-is.
New stuff:
View#find
andView#findAll
as great shortcuts forquerySelector
/querySelectorAll().toArray()
. I'm using these names because these are native methods onElement
since this spec and because they are short and concise.utils.delegate
andutils.undelegate
for native event delegation.utils.matchesSelector
andutils.ajax
for fast and convenient minimal selector matching / XHR shortcut.Backbone.Deferred
for custom deferred libraries (I think this is a big deal since Chrome now has native promises, other browsers will soon have too)View#useNative
property if you still want to include jQuery but also want to use native methods for some particular views (hot code)Behaviour in no-jquery env:
View#$el
.:first
) and event namespaces (click.ns
), I think it's pretty obvious — if you want them, use jQ. Ordinary event delegation and bubbling works just like before.Native DOM view tests are in
test/no-jq.html
andtest/view-no-jq.js
.