Building a Slimmer jQuery
jQuery is more than five years old now! Over that time it has evolved along with the browsers, web sites, devices, developers, and users that it serves. It has also, um, grown quite a bit over that time. jQuery has added a lot of useful features, but it’s also accumulated cruft that we’d prefer not to support into perpetuity. It may not be an issue on a desktop PC with a high-speed connection, but we want jQuery to be a good solution for mobile devices as well.
Along with our continuing push for higher performance, our priority for upcoming versions is a smaller gzipped file size. It’s hard to do that when every new feature or bug fix must also preserve all existing features and behavior. So today, we want to start a conversation about slimming down the jQuery API by deprecating some features. Here are our guidelines for deprecation:
- We don’t believe the feature represents current best practice in the use of jQuery.
- The feature has proven unpopular, confusing, inefficient, or ineffective in actual use.
- It is not practical or feasible to enhance the feature or address its limitations.
- Removing it at some future time could yield notable usability, size, or performance benefits.
Deprecation is just the first step in a process that you can participate in. It is our goal to:
- Explain the reasons for deprecating a particular feature, as described above.
- Give at least one major-point-version, and often more, between deprecation and removal.
- Provide alternatives to deprecated features so that migration is not painful.
- Listen to community feedback regarding deprecation and removal.
Occasionally, as in the situation with event.layerX/layerY in version 1.7, we will make a breaking change with shorter notice if we judge that it will cause less pain to remove the feature immediately than to leave it in. Those will hopefully be rare exceptions.
Version 1.7 Deprecations
With those things in mind, we consider the following features to be deprecated as of version 1.7. Existing code that uses them continues to work, but the recommended alternatives are a better choice for compatibility with future versions.
.live() and .die(): We continue to get many bug reports and see user confusion regarding the quirks of the .live() method. Common issues are now documented on its updated API page. We strongly advise the use of .on() or .delegate() for new code, since they are better APIs. Given its widespread use it’s unlikely we will remove this API in 1.8, but please do update your code as soon as possible.
Non-standard event properties: As part of our push to improve event handler performance, we are also deprecating the copying of several event properties from the native event object to the jQuery event object and will remove them in 1.8: attrChange, attrName, relatedNode, and srcElement. Instead of accessing these through event.NAME
you can access them via event.originalEvent.NAME
where needed.
$.ajax() Deferred aliases: In version 1.5 we defined .error()/,success()/.complete() on the jqXHR object as aliases for the Deferred’s .fail()/.done()/.always() methods. Although that seemed like a good idea at the time, it makes jqXHR a non-standard Deferred. That’s not good. Whenever possible, use the deferred/promise method name in preference to the jqXHR one. We still have some work to do here to provide a full migration path, so we are likely to continue supporting the aliases past 1.8.
deferred.isResolved() and deferred.isRejected(): Now that Deferreds and Promises have progress notifications and a convenient .state() method, we are deprecating these older methods and will remove them in 1.8. Getting the state of an N-state object using N-1 Boolean methods is a cruel-code version of “Twenty Questions”. Deferred-based code rarely needs to inspect state, and the string returned now is more convenient for a debugging scenario where it’s often used.
.attr(“value”) on inputs: For backwards compatibility, we’ve been returning the current value here (as in “what is currently in the input box”) versus the real attribute (what the value
attribute says in the HTML). That leaves us no way to provide the true attribute value, and is confusing since W3C selectors work on the attribute and not the current value. So we are deprecating this behavior and will remove it in 1.8. Always use the .val()
method to get the current live value of an input element. Until we can reclaim the attribute, you can use $("selector")[0].getAttribute("value")
except on IE 6/7 where that will still return the current value. (Our 1.8 solution will get the attribute value on all browsers and is another reason why we’re anxious to change this.)
.closest(Array) returning Array: This signature is a bit of a strange bird, it was created for use by the old live events code but it returns an Array rather than a jQuery object. As of 1.8 we plan to remove it. The other signatures of .closest()
are here to stay and are not affected.
.data(“events”): jQuery stores its event-related data in a data object named (wait for it) events
on each element. This is an internal data structure so in 1.8 this will be removed from the user data name space so it won’t conflict with items of the same name. jQuery’s event data can still be accessed via jQuery._data(element, "events")
but be aware that this is an internal data structure that is undocumented and should not be modified.
$.sub() as a plugin: Although $.sub()
can be useful for creating interference-free zones for plugins, it is not used by jQuery core and not widely used by other code, so we intend to transition it to a plugin in version 1.8 to save space.
Looking Towards jQuery 1.8
Given our push for a svelte jQuery, the filter for new features in 1.8 will be stringent. Even performance-related proposals need to be balanced against the space they use or save. Features that can be implemented via plugins, special events, attribute hooks, or other jQuery extension mechanisms are likely to stay outside core for now.
That brings up the question of what we could deprecate in 1.8 and eventually remove to simplify and streamline the library. Those things don’t have to totally disappear; they could move into a separate plugin, for example, and only be included when needed. Take a look at how you use jQuery, and talk about it with your colleagues.
Within a few weeks, we’ll be opening the call for your ideas concerning jQuery 1.8 with another blog post — so start thinking about it now!
Edit: No, we’re not removing IE6 support yet, and we can’t. As John Resig mentions at every jQuery Conference, most of the sins of IE6 are also visited upon IE7 and IE8, which together still have more than one-third of desktop browser market share. It doesn’t make sense to remove support for IE6 until we can whack IE7 and IE8 as well.
Release a “slim” version of Jquery and then a “full” version that supports everthing. You should not cut out support for these browsers just yet. You just don’t know who will need it.
I think you should greatly reduce the animation support, and only provide rudimentary fade in/out in core.
You DO have jQueryUI, which was made for such things.
@Daniel
Have you tried compiling your own version of jQuery, picking & choosing what you wish to use? I’m willing to bet that it won’t be as easy as you suggest due to the way in which modules are freely shared within other modules.
Happy to see live()/die() deprecated, but I’d love to see bind() and delegate() deprecated too (and possibly even deprecate the bind shortcut methods). There is a huge value in consolidating event handling to a single set of powerful methods – especially for non-programmers and users that are new to the library.
+1 about removing $.browser: browser sniffing is a bad practise, and we should avoid it
Is anybody using this the filter for “radio, checkbox, file, password, submit, image, reset, button”? I even didn’t know, this works as I use input[type=”checkbox”].
I am strongly hoping to separate the jquery into two parts, one without relating DOM but only object related functions, the other one with DOM related functions.
The part without DOM related things is crucial when we are using Web workers. With the increasing use of the web worker applications, the utilities of manipulating objects seem more important.
What about jquery.html5.js version? Smaller subset and new html5/css3/javascript engines support and GPU acceleration. jquery.html5.js for new browsers: IE 10+, Firefox 9+, Google Chrome 17+, Opera 12+ and jquery.html4.js with same functions for older browsers. Maybe jquery.compatibility.js for old and deprecated functions.
While earlier versions of jQuery were valuing above all backwards compatibility, we are seeing a trend of breaking this in latest revisions, and now of even removing backwards-compatible “old bad stuff”. While it’s good to keep things slim, it is a huge headache in frameworks including many “modules” needing to run together like in Drupal or in Community Builder.
Thus I would suggest following (I haven’t seen it proposed above, hope i didn’t overlook that proposal):
1) slim down jQuery to what is it’s ideal API for the given version without any backwards support.
2) add a jQuery-compatibility plugin for that version that does restores backwards-compatibility for sites where it’s needed, and add in that a debugging tool which lists backwards-compatibility issues that it had to fix to help improve API of other plguins and jQuery-uses.
That way, you get a slim, modern jQuery, and don’t loose the wider use of jQuery and headaches when in our framework we try to keep old and new extensions using jQuery run smoothly.
What do you think of that proposal ?
To go really really fast and get rid of all that cruft, and also all those unused things many sites do not need i suggest:
Short Term:
1) Flag items in you build as obsolete
* You can then generate a “compatible” version, and a “slim” version
* Everybody is happy
Long Term:
1) Do what jQueryUI/Modernizr is doing
* Get that custom build page up, and let users chooses the features they need !
* Everybody is really really happy
To me, these are about the only things really needed to cater to just about everybody’s needs..
please remove support for IE6, IE6 came in 2001, so it’s now 10 years old! please leave IE6 and move on
Do not remove $.browser, because it is still necessary sometimes for fixing browser-bugs. Not everything can be done with feature-detection.
@Beat:
I like the idea of a compatibility plugin, or “jQuery legacy plugin”. All current and future deprecated stuff could be dumped in it.
This way, if you really want a lightweight jQuery file, you have all the time to update your code to the latest APIs.
Support for IE6 has to stay around till we can drop support for IE7 and IE8.
Breaking jQuery apart into modules similar to jQuery UI is pointless. If you want a crippled version of jQuery, use some external project such as jSlim to remove the stuff you don’t use or use another library entirely. It is actually less efficient to use your own slimmed down version of jQuery than it is to use the version from the CDN since more than likely the version from the CDN will be cached before the user even visits your site.
Why don’t we break up the jquery code into browser-specific versions, each smaller and performing faster. Upon loading a website, browser should be checked and the appropriate small library should by loaded.
Also, I’m not very familiar and aware of functions i do not use. Shouldn’t we scan/vote for functions we use most, c.q. want most?
Further, i would support some powerful core functions and put shortcuts in a seperate library. Examples:
– keep toggleClass; plugin for AddClass/removeClass
– keep SlideToggle; plugin for SlideDown/SlideUp
– keep FadeToggle; plugin for FadeIn/FadeOut
– keep $.ajax; plugin for $.put, $.get
– keep .is(); remove .hasClass()
@Kevin
We don’t use jQuery via CDN anymore because every once in a while it would go unresponsive.
At least Google was having these hiccups a few months back, and with 8Million unique visitor/month website, this is just unacceptable. So now we just precache it on our own servers, slap a long expiration header on it, and if it still goes down, at least we know who’s fault it is :)
Though we will probably switch back to something more like this soon:
http://css-tricks.com/snippets/jquery/fallback-for-cdn-hosted-jquery/
Eli Perelman wrote:
> One reason for jQuery’s proliferation is its ability to be accessible from a CDN and improve site performance because of its cache inclusion.
This is spot on, but I wonder if there is a way to appease both crowds? I’m likely to only include the CDN version, which tends to be blazing fast because it’s cached by everyone, but I can understand the desire for modularization if you’re going to be hosting it yourself. Could we just CDN Jquery with all the modules, and then for download have selectable modules?
Thank you for not removing ie6 support! For our enterprise business it is CRITICAL that you guys support it. I really don’t know what I would do if you guys didn’t support, I don’t think any other toolkit is mature enough to work in. I’d probably recommend we move to Java swing if that happened.
Keep the selector engine, the events drop the rest
I agree with T.J. Crowder.
I’m working at BT (British Telecom), a leading company.
And our company is not ready to leave Internet Explorer.
For now, the only allowed versions of IE on our computers are IE6 and IE7. Only for “security reasons”.
And all the new applications are still warranted to work on those versions.
Few chances that it changes in a near future… for the big regrets of many of us.
So, with the idea that things may change one day, i make all my developpements compatible with all others browers, still hoping one happy day, IE will be banned, for the reason it’s not respectful of the W3C recommendations.
33,285 bytes (32.50 KB) when gzipped and minified isn’t exactly big… I read somewhere that the iPhone used to cache files of 25kb but now it’s more like 4mb?
So with that in mind… I’m not really bothered about the size of jQuery, there are bigger things to worry about. When your site consists of many large promo items then these alone are about 60-100kb each and they aren’t already cached from visiting another site like jQuery is.
I currently have everything in one bundle with head.js but I think in that case I should be utilising people already having cached jquery. Another 32kb download inside my bundle vs another async request (if its not cached)…
My bundle file is probably about 100kb after minify/gzip with everything being modular like image-sliders, carousels, site specific things… Maybe I could replace alot of the core functionality from things like jQuery UI draggable, droppable, slideable etc
Modularize jQuery more, it should be more like jQuery UI in that sense.
You can still have your standard GOD object release, but I see alot of benefit if users could pick pieces they want/don’t want, to reduce the amount of code they deliver to users.
Removing the .error()/,success()/.complete() methods may save space but it also means we are moving these functions back to write more code vs the jQuery love of doing more with less code. This one seems like moving the wrong way IMO but understand we are looking everywhere we can to make things more mobile ready.
Mobile devices increase features fast. It would be interesting to see where this all plays out. This is especially true now that “Flash” is being pushed out of consideration. We will (the jQuery community) have an opportunity to fill the gap of those scrambling for a sustainable solution.
So we have jQuery Mobile, jQuery as both being mobile device considerations. Will jQuery UI be a mobile consideration? When does that apply or does it? Seems someone who might have researched this could come up with some guides and/or unit tests on this. If they did it would help the community greatly! (beyond my immediate scope or would be glad to do this)
Will there be any changes to .offset()? Can it be assumed that there’s support for getBoundingClientRect? That’s a lot of code!
I think there is no good alternative to $(…).live() yet. For instance, how would you convert the following snippet?
$(‘my-long-selector-here’)
.live(‘click’, onClick)
.live(‘change’, onChange)
From what I understand, I guess you think we should write it as
var s = ‘my-long-selector’
$(document).on(‘click’, s, onClick)
$(document).on(‘change’, s, onChange)
Really?!
I vote for dropping IE6 support. It will become the tipping point. jQuery library is the most popular in web development and it has the power to influence the industry towards innovation.
Or even:
var s = ‘my-long-selector’
$(document)
.on(‘click’, s, onClick)
.on(‘change’, s, onChange)
It doesn’t matter. What bothers me is having to repeat the selector…
Agree, it would be nice to have IE6 support as an external library just like jQuery UI has been taken apart from the core library.
This surely will make a slimmer jQuery for lots of people.
Please consider bandwidth / latency before breaking stuff out into separate modules. The minified / gzipped version has grown three-fold. In the same period my bandwidth has increased twelve-fold. Breaking stuff out might save 2k or 3k of size, but might end up costing a lot more in terms of overall network time. In any case, with CDN version… size currently not a big deal.
The effects API goes from line 8273 to 8903 in jQuery 1.7:
16 kB unminified = 6,7 kB minified (saved), 3,2 kB minified+gzipped (saved) => 10% smaller jquery-1.7.min.js.gz (29,2 kB)
If you want to remove parts of the API by all means do so, but make this the beginning of jQuery 2 and leave the 1.x branch as it is. It will confuse the hell out of developers if the next release in the 1.x branch no longer has functions or behavior that are documented in books and throughout the web in tutorials etc.
My advice: start a fork now and call it jQuery 2, do some preview releases etc. and have a separate page on the website. Keep 1.x as it is now with continued new features and patch releasing.
This way the version numbering will conform with semantic versioning – http://semver.org/ which most developers are familiar with (even though they may not know what it is called).
See Python 2 -> Python 3 as a good example where you can have a non-backwards compatible release but you can also back-port new features into the older branch and maintain it.
One way to slim down the api is to deprecate and remove the vast array of method aliases.
* All of the event short forms are duplicated by .on/.trigger.
* All of the various .ajax aliases like .get() and .post() are all limited/inconsistent duplications of the .ajax().
* hasClass duplicates .is().
Having fewer ways to do the same thing is one way to help reduce jQuery’s size on the wire. Deprecating/Removing features should be done in a 2.x release though. Breaking changes without a version bump can make for confusing upgrades.
Good initiative, although I don’t see the current filesize as a problem.
However, removing IE6 support, at the moment, would be a big blow.
Please put in the API a note on everything that is deprecated from now on! Most people don’t read the blog, they just look things up in the API. Thank you for your hard work!
I think the idea of jQuery build system where you choose what functionality. would be a better idea.
I Had 1.6 separated to two JS files by 14kb it work great
how i do this
simple
jq.js – string with eq asd = ‘jQuery.extend=jQuery.fn.extend=function(){v….
then in
realq.js —
// [[Class]] -> type pairs
class2type = {};
eval(asd);
use eval and put code into string :)
For my opinion please not slim just separated to two files by ~14kb
About hasClass vs is, keep in mind hasClass is faster.
I recently gave a DC jQuery Meetup talk about ways to avoid jQuery when you don’t need its full power. For example, I talked about using Sizzle to get arrays of DOM elements by CSS selector, if you don’t need jQuery-specific features and if don’t mind the effort of coding old-school loops over arrays. So I’ve been thinking for quite a while about using Sizzle() when jQuery isn’t loaded and using $.fn.find() when it is.
Since the same folks are involved in both jQuery and Sizzle, and since Sizzle is already available externally (self-contained), it makes sense to modularize this aspect early-on. Suggestions:
(1) Create a minified version of Sizzle and make it available in the jquery-sizzle-version-xxx.zip file. (I minified it with YUI Compressor for my own use, but others need a minified version too.)
(2) Add AMD API support to Sizzle.
Uncompressed minified Sizzle is 1/6th the size of uncompressed minified jQuery, so we’re talking about a significant amount of code that’s already modular.
TL;DR applies here.
I did read a fair bit of the conversation however, and I like the idea of creating a 2.0 version that ditches support for older browsers, not just IE. The is no reason I can see not to do this. Dev’s that require support for older browsers, and any depracated features simply use pre V2.0. thats it, Job done. Then we can all move on.
Just my 2p.
I have noticed one interesting behavior in jQuery 1.7 in difference to 1.6, maybe someone can help me identify wheter it is a bug or part of deprecation?
The following snippet checks a checkbox and then unchecks it (don’t mind the selector – it’s illustratory):
$(‘input[type=checkbox]’).attr(‘checked’, ‘checked’);
$(‘input[type=checkbox]’).attr(‘checked’, ”);
Well in 1.7 the second line won’t work. It does not destroy the attribute – rather it sets it value to “”. So it’s still checked.
Of course probably the right way to write this is .removeAttr(‘checked’), but why the previously mentioned snippet stopped working?
Mark story wrote:
> * hasClass duplicates .is().
I disagree, hasClass() is MUCH faster than is():
http://jsperf.com/jquery-hasclass-vs-is-performance/2
Happy to hear talk of jQuery being slimmed down.
Totally agree with Alistair and others that $.browser can go. As it says in the docs, best to feature detect instead.
In cases where you have no choice but to browser sniff, I’d say it’s better to do it server-side from the headers and put a data- attribute on the html element. Much cleaner.
I agree that if significantly breaking the API, just call it 2.0. This means people starting a new project grab the latest and never worry about backwards compatibility.
I like the ideas of modularization (like the earlier poster I never use all of jQuery in every project). Make the first module a jQuery 1.x migration module. Make the jQuery 2.0 core real lean and mean on mobile.
The arguments of “don’t worry about file size just use a CDN” are fine and good on the desktop, but it doesn’t work that way with mobile. Often caches are expunged much more frequently. And the total size which can be cached is smaller. jQuery often tips over that mark and is not cached.
Counter-arguments about multiple network connections for modules are silly because people can always choose to concatenate smaller script files.
jQuery 2 IMHO should:
1. Support just HTML5/CSS3/JS1.9
2. Advocate ChromeFrame for our poor IE users (it is time to say, IE10 or bye, bye IE so that we can really innovate)
3. Use AMD for modular support
I’m now advocating the above 3 points for our enterprise customers and I feel that jQuery in its current form will become less relevant given such an environment.
I used to use jQuery for it’s small size and nifty features. Then it grew into the biggest file on my server (besides the offered downloadable ZIP files), so I started abandoning jQuery more and more.
Why not do it like “modernizer” does it? Give us a bunch of checkboxes and let us choose what we – the users/designers/developers – want and need. Nothing more, nothing less.
Or, wrapping up the multiple comments above which I agree to in a more dramatic, single line of text: “modularize or die”.
Name it 2.0,
Make IE6 a plugin,
Make IE7 a plugin,
Make XML / XPath a plugin,
Only load Sizzle when native querySelectorAll is unavailable (not easy to do but worth it imho)
Reduce core and make many more things “pluggable”.
It is Good News to hear that jquery is going to support mobile phone web browsers too.. Ofcourse it is better to deprecate unused functions that are available in jquery old version, so that jquery will be made to be small size and more efficient. My best regards to Jquery
For certain tasks, all I want is a version with the API (selection of functions) of Zepto.js but with IE compatibility. Been considering making my own, but I don’t want to have to refactor my own work each time I want to inherit improvements in jQuery. Will it need a whole modularized system? I don’t think so.
Regarding live/bind/click etc., I agree that all we need is on/off. On the other hand, most of these are now just aliases, which take up about 10 lines of code or so. Getting rid of them will not provide a noticeable slimming effect.
Someone suggested removing .each(), and it has to be said that .each() is about the least efficient iterator you can use. But when “5 times slower” still works out to milliseconds, I don’t mind the convenience. I wouldn’t want to see .each() go.
In my opinion the IE6 is more than outdated and shouln’d used anymore. So it will be nice to remove the IE6 support, too.
Put ie6 support into a plugin, so if you need it, just add the plugin and it works like it always has…. ie should be axed from existence for the vomit they continue spewing all over themselves. ie is disgusting.