An Ode to jQuery (and a 1kb alternative!)
Tags: javascript, watercooler, webdev, discuss
Published: 2021-11-18 11:15:33

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](https://github.com/dciccale/ki.js/) and works in IE9+ (you can make it much simpler if you don't need IE support!).

``` javascript
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);
        }
      });
    };
  });
}

```

### 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:-

``` javascript

$.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;
};
```
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 

{% post https://dev.to/ben/do-you-still-work-with-jquery-4o3g %}

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