Skip to content
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

Discuss - Removing jQuery as a hard dependency #980

Closed
jamesplease opened this issue Mar 5, 2014 · 32 comments
Closed

Discuss - Removing jQuery as a hard dependency #980

jamesplease opened this issue Mar 5, 2014 · 32 comments
Milestone

Comments

@jamesplease
Copy link
Member

This is a place to discuss removing jQuery as a hard dependency. Inspired by a comment @cobbweb made somewhere about doing this for v2.

List of jQuery features used by Marionette

  • $.Deferred
  • $(selector)
    • Possible replacement: Vanilla js
  • $el.html()
    • Possible replacement: Vanilla js
  • $el.empty()
    • Possible replacement: Vanilla js
  • $el.append()
    • Possible replacement: vanilla js

Locations of jQuery in the source

Will be updated with exact links soon

  • Marionette.Callbacks - $.Deferred
  • Marionette.Regions - $.empty()
  • Marionette.TemplateCache - $.html()
  • BindUIElements - $(selector)
    • Possible replacement: Just return the el if $ is undefined
  • Marionette.ItemView - $.html()
  • Marionette.CollectionView - $.append()
  • Marionette.CompositeView - $.html() $.append()

Seems doable if we wanted to go down this path. I have no opinion on the matter; I'm just fine leaving jQuery the way it is.

@cobbweb
Copy link
Member

cobbweb commented Mar 5, 2014

👍

Basically what I want is to load something like deferred-js and then use a micro-library like saltjs and not need jQuery :) Would require a bit of polyfilling in Backbone but it will be easier once jashkenas/backbone#3003 lands.

N.B. People just default to jQuery straight away for the simplest things when most of us are dealing with modern browsers, I think we need to get out of this habit. I'm also not a fan of jQuery's API. And it's slow.

@brian-mann
Copy link

$.html and $.empty do a lot more under the hood than you would probably
imagine. Replacing those with vanilla JS is easy except when you consider
removing all the events, DOM listeners, data, and such. Forget about those
and you'll have memory leaks galore.

On Tue, Mar 4, 2014 at 7:33 PM, Jmeas Smith notifications@github.comwrote:

This is a place to discuss removing jQuery as a hard dependency.

These are the places where Marionette explicitly uses jQuery:

  • Marionette.Callbacks - $.Deferred
    • Possible replacement: ES6-promise polyfill
      https://github.com/jakearchibald/es6-promise
      • Marionette.Regions - $.empty()
    • Possible replacement: Vanilla js
      • Marionette.TemplateCache - $.html()
    • Possible replacement: Vanilla js
      • BindUIElements - $(selector)
    • Possible replacement: Just return the el if $ is undefined
      • Marionette.ItemView - $.html()
    • Possible replacement: Vanilla js
      • Marionette.CollectionView - $.append()
    • Possible replacement: vanilla js
      • Marionette.CompositeView - $.html() $.append()
    • Same as above

Seems doable.

Reply to this email directly or view it on GitHubhttps://github.com//issues/980
.

@samccone
Copy link
Member

samccone commented Mar 5, 2014

+1 to @brian-mann

Topically this sounds like a good idea, however when you understand what these methods are actually doing , you quickly realize the WORLD of trouble you are opening yourself to.

I love this google doc that explains how silly http://youmightnotneedjquery.com/ really is, when you consider ditching the all mighty $.

https://docs.google.com/document/d/1LPaPA30bLUB_publLIMF0RlhdnPx_ePXm7oW02iiT6o/edit#

nuff` said

@cobbweb
Copy link
Member

cobbweb commented Mar 5, 2014

removing all the events, DOM listeners, data, and such

@brian-mann Isn't that because jQuery has it's own internal event bus and data management? If you bind with addEventListener and then do removeChild it will clear listeners.

This is what I gleaned from looking at jQuery source myself.

@brian-mann
Copy link

Yah. That's true. There are some other items on my mind but I'll research first before throwing out there.

Sent from my iPhone

On Mar 4, 2014, at 11:43 PM, Andrew Cobby notifications@github.com wrote:

removing all the events, DOM listeners, data, and such

@brian-mann Isn't that because jQuery has it's own internal event bus and data management? If you bind with addEventListener and then do removeChild it will clear listeners.


Reply to this email directly or view it on GitHub.

@cobbweb
Copy link
Member

cobbweb commented Mar 5, 2014

I'm all ears @brian-mann but if modern browsers can't add and remove nodes (which is the bulk of what we're doing) without causing memory leaks; I'm gonna give up and switch back to backend dev 😜

@akre54
Copy link

akre54 commented Mar 5, 2014

Anything to add before we merge jashkenas/backbone#3003 ?

@Anachron
Copy link

Anachron commented Mar 5, 2014

Just wanna throw minifiedjs into here:
http://minifiedjs.com/

@jamesplease
Copy link
Member Author

I still think this is viable. @brian-mann, have you had a chance to think more about this?

@Anachron
Copy link

Anachron commented Apr 1, 2014

I also want to throw this into:
https://github.com/jquery/jquery#how-to-build-your-own-jquery

However, I suggest just taking the parts that you actually need for Marionette.

@samccone
Copy link
Member

as @akre54 mentioned, this is going to be a problem quite soon for us

https://github.com/jashkenas/backbone/wiki/Using-Backbone-without-jQuery
due to jashkenas/backbone#3003

So we need to resolve this for 2.x

@samccone samccone added this to the v2.0.0 milestone Apr 12, 2014
@jamesplease
Copy link
Member Author

I believe it is highly unlikely that this will be resolved by v2.

@samccone
Copy link
Member

ha yeah just we should not bump the backbone dep again until this is.

@jamesplease jamesplease removed this from the v2.0.0 milestone Apr 15, 2014
@akre54
Copy link

akre54 commented Apr 15, 2014

As I said, feel free to bump the BB version for whatever reason. This
change shouldn't affect anyone using jQuery. When Marionette is ready to
make jQuery optional, Backbone will provide the base.

@jamesplease
Copy link
Member Author

👍 @akre54, that makes sense.

@samccone pointed out that we rely on Backbone.$ for our jQuery methods...so it might not be that simple

@jamesplease
Copy link
Member Author

I'm wondering if we should add jQuery as a hard dependency until this gets worked out...Marionette now really does rely on jQuery.

@cobbweb
Copy link
Member

cobbweb commented Apr 22, 2014

I guess we'll defer this until v3?

@cobbweb cobbweb added this to the v3.0.0 milestone Apr 22, 2014
@samccone
Copy link
Member

$.defer

@jamesplease
Copy link
Member Author

$.defer

lol

yeah I think v3 at the earliest makes sense :P

cmaher added a commit to cmaher/backbone.marionette that referenced this issue Jun 2, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Promise#done() is not part of the standard and has different meanings in
different promise libraries.

This fixes the Deffered dependency discussed in marionettejs#980. This also exposes
Marionette.Deferred as a means to configure the desired implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
cmaher added a commit to cmaher/backbone.marionette that referenced this issue Jun 3, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in marionettejs#980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
cmaher added a commit to cmaher/backbone.marionette that referenced this issue Jun 3, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in marionettejs#980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
samccone pushed a commit that referenced this issue Jun 3, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in #980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
samccone pushed a commit that referenced this issue Jun 4, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in #980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
samccone pushed a commit that referenced this issue Jun 7, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in #980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
samccone pushed a commit that referenced this issue Jun 13, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in #980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
samccone pushed a commit that referenced this issue Jun 17, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in #980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
samccone pushed a commit that referenced this issue Jun 17, 2014
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in #980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
@jamesplease
Copy link
Member Author

The first step toward solving this issue was done via #1395. $.Deferred can be swapped for any thenable!

@samccone
Copy link
Member

samccone commented Jul 8, 2014

the slow road ahead 🚜

@jamesplease
Copy link
Member Author

rofl

@cmaher
Copy link
Member

cmaher commented Jul 8, 2014

Is the general idea going forward to provide a set of hooks a la https://github.com/jashkenas/backbone/wiki/Using-Backbone-without-jQuery, or just use raw DOM access when needed? Right now, there are a few examples of everything throughout the code. It might make sense to consolidate all DOM manipulation to some helper methods to both provide view hooks and remove jQuery.

@samccone
Copy link
Member

samccone commented Jul 8, 2014

Not sure the payoff would be so large vs the time to do this...

Perhaps we should ask the question why do we want this

@jamesplease
Copy link
Member Author

Perhaps we should ask the question why do we want this

Good idea.

The real problem I want to solve is the mismatch between the dependencies stated in the Backbone/Marionette manifests and the code you find in the library.

  1. Backbone does not depend on jQuery, so it doesn't pull it in.
  2. Marionette relies on Backbone's $ being jQuery, so it also doesn't pull it in.

This can be frustrating when trying to set things up in a CommonJS environment. I'd like to see our dependencies line up better with the code. There are two solutions I see to this:

  1. Move away from Backbone.$ being jQuery.
  2. Stop referencing Backbone.$ entirely and just make a new Marionette.$ that is jQuery, then add jQuery to our list of dependencies.

Re: @cmaher: either would be fine for me so long as it resolves the above problem.

@jamiebuilds
Copy link
Member

Stop referencing Backbone.$ entirely and just make a new Marionette.$ that is jQuery, then add jQuery to our list of dependencies.

but but...

@jamiebuilds
Copy link
Member

I think we should provide hooks like Backbone for methods that depend on jQuery functionality (and minimize the ones that do), then default to using Backbone.$. That way they can be overwritten just like Backbone.Native does.

I'd like to have an investigation as to what methods currently depend on Backbone.$/jQuery.

@cmaher
Copy link
Member

cmaher commented Aug 12, 2014

Just did an updated audit of all of the jquery/dom code at the HEAD of minor. Here's what I came up with:

Breakdown by file

Behavior

  • $ (local find)

CollectionView

  • document.createDocumentFragment
  • DocumentFragment#appendChild
  • jquery.fn.append(element)
  • jquery.fn.before(element)

CompositeView

  • jquery.fn.html(newHtml) -- attachElContent
  • jquery.fn.append(element) -- attachBuffer
  • $ (local find)

domRefresh

  • $.contains

Region

  • instanceof $ to determine jqueriness
  • $ (global find)
  • DOMNode#innerHTML=
  • DOMNode#appendChild

TemplateCache

  • $ (global find)
  • jquery.fn.html()

View

  • event.preventDefault
  • event.stopPropagation
  • $ (local find)

Summary

  • local find: this.$(selector)
  • global find: $(selector)
  • set inner html: html(e), innerHTML=
  • get inner html: html(), innerHTML
  • append element: append(e), appendChild(e)
  • add element before another: before(e)
  • one element contains another: contains(e)
  • is an element jquery-ified?: instanceof Backbone.$
  • create performant unattached node: createDocumentFragment

Going forward

  1. Provide hooks that wrap around jquery/dom manipulation, delegating to backbone when possible -- can be done in v2.x
  2. investigate possibility of supporting only jquery or dom (or keep both and make sure to distinguish when to use one method over another, i.e. jquery for when you have to be careful about memory leaks) -- should be delayed until v3

@jamesplease
Copy link
Member Author

Awesome work, @cmaher. Feel free to update the initial message with the latest audit.

@jamesplease
Copy link
Member Author

Added to #1796

@paulfalgout
Copy link
Member

@marionettejs/marionette-core do we need to readdress this?

@samccone
Copy link
Member

x-ref
#2300

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

10 participants