DEV Community

Cover image for An Ode to jQuery (and a 1kb alternative!)
GrahamTheDev
GrahamTheDev

Posted on

An Ode to jQuery (and a 1kb alternative!)

When jQuery came out it really was spectacular,
it gave developers a common Vernacular,
But times have changed and the year is 2021,
and the time for jQuery has passed and gone.

I do not want you to think that I hate or despise
an essential piece of internet history (at least in my eyes)
but if you are using it to build your brand new site
I hate to tell you but it is probably shite.

jQuery adds bloat and it ruins your web vitals,
You don't need 252kb of JS just to adjust the titles,
instead use vanilla JS and querySelectorAll
and watch your package size fall and fall!

"But I like the syntax" I hear you say!
Well let me show you another way.
In just 1.4kb of vanilla JS,
I can show you the way to performance success!

The code you can use instead is below,
allowing you to keep your current workflow,
but you can save those bytes to make performance better,
and still use the dollar sign as your global selector.

So here is the answer that will address your need,
for an extensible micro library that improves site speed,
the speed you need if you want your site to rank well
so you gain more visitors, increasing your chances...to sell.

Yeah, I am not a poet!

My poetry sucks, but I can show you an alternative to jQuery for a lot of needs (simple sites and side projects, not for complex stuff FYI!) that is 1400 bytes (600 bytes gzipped!) of JavaScript.

It is a modified version of a library called ki.js and works in IE9+ (you can make it much simpler if you don't need IE support!).

if (typeof $ == "undefined") {
  !function (b, c, d, e, f) {
    f = b['add' + e]
    function i(a, d, i) {
      for (d = (a && a.nodeType ? [a] : '' + a === a ? b.querySelectorAll(a) : c), i = d.length; i--; c.unshift.call(this, d[i]));
    }
    $ = function (a) {
      return /^f/.test(typeof a) ? /in/.test(b.readyState) ? setTimeout(function () {
        $(a);
      }, 9) : a() : new i(a);
    };
    $[d] = i[d] = {
      on: function (a, b) {
        return this.each(function (c) {
          f ? c['add' + e](a, b, false) : c.attachEvent('on' + a, b)
        })
      },
      off: function (a, b) {
        return this.each(function (c) {
         f ? c['remove' + e](a, b) : c.detachEvent('on' + a, b)
        })
      },
      each: function (a, b) {
        for (var c = this, d = 0, e = c.length; d < e; ++d) {
          a.call(b || c[d], c[d], d, c)
        }
        return c
      },
      splice: c.splice
    }
    }(document, [], 'prototype', 'EventListener');
  var props = ['add', 'remove', 'toggle', 'has'],
      maps = ['add', 'remove', 'toggle', 'contains'];
  props.forEach(function (prop, index) {
    $.prototype[prop + 'Class'] = function (a) {
      return this.each(function (b) {
        if (a) {
          b.classList[maps[index]](a);
        }
      });
    };
  });
}

Enter fullscreen mode Exit fullscreen mode

What functions do I get?

Right out of the box this gives you most things you need.

You get:

  • $() selector
  • .on()
  • .off()
  • .each()
  • .splice()
  • .addClass()
  • .removeClass()
  • .toggleClass()
  • .hasClass()

And then you can extend it with a few extra useful functions:-


$.prototype.find = function (selector) {
  return $(selector, this);
};
$.prototype.parent = function () {
  return (this.length == 1) ? $(this[0].parentNode) : [];
};
$.prototype.first = function () {
  return $(this[0]);
};
$.prototype.focus = function () {
  return this[0].focus();
};
$.prototype.css = function (a, b) {
  if (typeof (a) === 'object') {
    for (var prop in a) {
      this.each(function (c) {
        c.style[prop] = a[prop];
      });
    }
    return this;
  } else {
    return b === []._ ? this[0].style[a] : this.each(function (c) {
      c.style[a] = b;
    });
  }
};
$.prototype.text = function (a) {
  return a === []._ ? this[0].textContent : this.each(function (b) 
  {
    b.textContent = a;
  });
};

$.prototype.attr = function (a, b) {
  return b === []._ ? this[0].getAttribute(a) : this.each(function (c) {
    c.setAttribute(a, b);
  });
};
$.param = function (obj, prefix) {
  var str = [];
  for (var p in obj) {
    var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
    str.push(typeof v == "object" ? $.param(v, k) : encodeURIComponent(k) + "=" + encodeURIComponent(v));
  }
  return str.join("&");
};
$.prototype.append = function (a) {
  return this.each(function (b) {
    b.appendChild(a[0]);
  });
};
$.ajax = function (a, b, c, d) {
  var xhr = new XMLHttpRequest();
  var type = (typeof (b) === 'object') ? 1 : 0;
  var gp = ['GET', 'POST'];
  xhr.open(gp[type], a, true);
  if (type == 1) {
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  }
  xhr.responseType = (typeof (c) === 'string') ? c : '';
  var cb = (!type) ? b : c;
  xhr.onerror = function () {
    cb(this, true);
  };
  xhr.onreadystatechange = function () {
    if (this.readyState === 4) {
      if (this.status >= 200 && this.status < 400) {
        cb(this, false);
      } else {
        cb(this, true);
      }
    }
  };
  if (type) {
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send($.param(b));
  } else {
    xhr.send();
  }
  xhr = null;
};
Enter fullscreen mode Exit fullscreen mode

That gives you:-

  • .find()
  • .parent()
  • .first()
  • .focus()
  • .css()
  • .text()
  • .attr()
  • .param()
  • .ajax()

All for an additional 2000 bytes (900 bytes gzipped)!

What more do you need?

Those are the top 90% of jQuery selectors that people need, and it lets you keep the jQuery syntax if that is what you prefer.

All for 1.3 kb gzipped! (or 3.3kb raw).

It is worth noting that it isn't a drag and drop replacement, there are some slight nuances when it comes to single item selection (you may need to use $('.item')[0] to select an item if you don't use .first() for example).

In fact, it isn't something I would recommend most people use, I am using it purely to give you an example of how you could start your own micro library (and introduce the idea of micro libraries in general to you!)!

Before the angry comments start!

Look, I am not saying "don't use jQuery", despite the tongue-in-cheek poem.

What I am actually saying is explore alternatives before just including jQuery in a new project.

Core Web Vitals and website performance are essential parts of success nowadays.

The easiest way to have a high performance site is to ditch heavy JS and unused code.

jQuery is still useful if you need to support older browsers / edge case browsers, so use it if it fills a need.

Also bear in mind that if you use code splitting and tree shaking etc. you can make jQuery performant still!

The same advice applies to using React for static sites.

React is obviously useful for SAAS products...but stop using it to build brochure sites. It is way too much JS to render a nav bar, hero image and a title.

Pick the right tool for the job and your life as a developer will not only become easier, but you will make faster sites that can be enjoyed by people even on a 3G connection!

I hope you enjoyed this silly article. We will see how many people actually read it when we read the comments! 😉🤣

P.S. this post was inspired by this post by @ben

You should go read the comments there as there are some interesting points about jQuery usage today!

Top comments (6)

Collapse
 
grahamthedev profile image
GrahamTheDev

If you want to see the original library: ki.js

And the original extended version: ki-extend.js they are really interesting for inspiration.

As I said, use carefully in production!

Collapse
 
honatas profile image
Jonatas de Moraes Junior

I'm really used to jQuery syntax because I've been a jQuery user for so long. It's really neat and it's hard to let go. Still trying to make good work of vanilla with typescript, but it is quite verbose. Maybe a few kbytes won't hurt the site's performance and will get me in a beter mood while coding. However, even before reading this article I was thinking of using this one here on my next project: npmjs.com/package/cash-dom

Collapse
 
siddharthshyniben profile image
Siddharth

This is cool! A bit ago I was thinking of building a jQuery like mini framework to make building plain HTML/CSS/JS sites a bit less painful, but I never did as my focus shifted to building a framework itself.

The code looks ingenious, was it hand golfed?


I hate to tell you but it is probably shite.

...
shite? lol

Collapse
 
grahamthedev profile image
GrahamTheDev • Edited

Shite is an English word (as in used in the UK in parts of England, not English the language 🤣) same as it is without the "e" but less offensive!

Yes ki.js was originally for code golf from what I gather, another reason why it isn't ideal for production (so for example I added a few tweaks to make it usable in the real world.)

Collapse
 
brewinstallbuzzwords profile image
Adam Davis

That's pretty neat. I use jquery at my job, so this could be handy for some small side projects where a more modern framework would be overkill.

Collapse
 
grahamthedev profile image
GrahamTheDev

Yeah, ideal use case for it! ❤