Custom Lightweight JavaScript Libraries: EnderJS and MicroJS

2.9k Views Asked by At

I'm working on a custom lightweight JavaScript library that will need to run stably across the major browsers as well as across numerous independent sites without compromising or being compromised by existing libraries or namespaces. Perhaps most importantly, the library will need to be lightweight (~15k max).

UPDATE To clarify the need for such a small library: This is a third-party service that sites would pull into their page. We need to keep everything as light-weight, speedy, and self-contained as possible since we have no control over the existent libraries, speed, or page load. 15k is the target number just for the library that is accessed by the dynamic content of the service.

At this point my idea is to start with the most condensed jQuery-like base I can find, and then extend with custom modules.

Desired features:

  • Handle cross-browser inconsistencies like a champ (IE 6+, Chrome, FF 2+, Safari 3+).
  • Event handling (queuing/binding/broadcasting)
  • Efficient selector engine
  • Chaining
  • DOM manipulation w/ basic animations
  • Readily build-able and version-able from modules

I've come across EnderJS and MicroJS but I can't seem to find a lot of discussion on either. I'm more familiar and interested in Ender at this point since it seems to address all of the above features almost out of the box with "The Jeesh" weighing in at 7.5k. Tacking on a couple additional packages only pushes it to 10k in my case which would be perfect since I should only need a few k to flesh out any custom modules. It also would allow me to write and version distinct modules that can be incorporated and compressed into the main library at build-time, as well as define a unique namespace to hold it all together and hopefully protect it. Another compelling piece to the Ender library is its use of NodeJS which I would love to play around with more anyway. Having said all of that, however, I am still wide open to other ideas.

So my question is:

Does anyone have any experience with either EnderJS or MicroJS, or have another solution/approach to what I'm trying to accomplish? I realize this is not the place for "chatty, open-ended questions", and that's not my intent here. I'm just looking for suggestions on the best way to approach building a light-weight custom library without reinventing the wheel and to instead plug into the most up to date micro-libraries available.

3

There are 3 best solutions below

4
0xDonut On BEST ANSWER

I've used Ender recently, and I've had no issues with it really. There are a couple of jQuery functions that aren't available from the off, but anyone who is fairly adept at JavaScript can circumvent this. Especially given the fact that Ender has a near identical structure and way of extending as jQuery.

I've used Ender on a live site recently and funnily enough I have used a couple of scripts from microjs.com alongside my own functions file, and all the JavaScript weighed in at around 15k. It's not hard to make your entire site code weigh around that or less.

As well as building a lightweight version of Ender, for example starting with the Jeesh, you might also want to consider async loading, an example is provided by Dustin Diaz:

<script src="ender.min.js"></script>

<script>
$.require('/js/core.min.js', 'core')

$.ready('core', function () {
  $(document).ready(function () {
    $('<p>hello world</p>').appendTo('body')
      .bind('click', function (e) {
        $.require('/js/ajax.min.js', function () {
          $(e.target).css('position', 'relative')
            .animate({
              left: 500
            })
        })
      })
  })
})
</script>

By doing this you could essentially make the original ender build even lighter, and defer some of the loading, but generally speaking, if it's light in the first place you should be ok.

You might also want to take advantage of the Google closure compiler that Ender gives you access to in order to compile your site code alongside ender.

Finally, as you're probably well aware, you can do noConflict in Ender as well, just in case they already have another library present.

As you build and configure Ender you will probably want to take advantage of ender-wallet which will give you a sort of API view, allowing you to remove libraries you might not need at all.

hotlinked screenshot:
screenshot

11
T.J. Crowder On

Given this:

To clarify the need for such a small library: This is a third-party service that sites would pull into their page. We need to keep everything as light-weight, speedy, and self-contained as possible since we have no control over the existant libraries, speed, or page load. 15k is the target number just for the library that is accessed by the dynamic content of the service.

I'd recommend using demand-loaded jQuery via one of the CDNs (Google's or Microsoft's; I think Google's is used more but you'd want to test). Your code can detect whether jQuery is already loaded and use it if so (~0k), and if not add a script element dynamically that pulls it from the CDN. If the user has visited any other site using jQuery from that CDN, then the script may well come from cache (~0k). If not, granted, then you have the ~31k rather than ~15k hit, but again, quite frequently you won't have any hit, or just the hit of a "not modified" response from the CDN.

You'd want to issue a noConflict call if you did load it, in case the site uses $ for something other than jQuery. That's readily done by watching for the load event on the script element (you have to use readystatechange on IE and watch for either loaded or complete status) and then doing it when that comes through.

In today's telecomms world, the difference between a 15k download and a 31k download is trivial compared with the cost of setting up the HTTP connection in the first place.

That demand-load really is a tiny bit of code, along these lines:

function loadJQuery(cb) {
    var d, s, t;

    if (typeof jQuery === "function"
        && parseFloat(jQuery.fn.jquery) >= 1.5) { /* Or whatever */
        window.ourjQuery = jQuery;
        if (cb) {
            cb();
        }
        return;
    }

    d = document;
    s = d.createElement('script');
    t = d.body || d.getElementsByTagName('head')[0] || d.documentElement;

    s.onload = loaded;
    s.onreadystatechange = handleReadyStateChange;
    s.src = "//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js";
    t.appendChild(s);

    function loaded() {
        if (s) {
            s = undefined;
            window.ourjQuery = jQuery.noConflict(true);
            if (cb) {
                cb();
            }
        }
    }

    function handleReadyStateChange() {
        if (s && (s.readyState === "loaded" || s.readyState === "complete")) {
            loaded();
        }
    }
}    

Note the URL on the script element. That's so it's friendly to both http and https pages (details). Note also that I'm checking for a minimum jQuery version and using the more rigorous form of noConflict if we load it. Either way, by the time the callback is called, the ourjQuery symbol refers to the loaded copy with the minimum version.


Update: Addressing your comment above:

That's a good idea but unfortunately not really an option for us. I agree jQuery from Google's CDN would most likely be cached - saving load - and that we could check and extend as needed, but it doesn't seem as scalable or stable as serving it ourselves. The site could decide to overwrite some jQuery module to suit their needs or worse. What we need is a light-weight self-contained library that we have complete control over and can extend and branch as needed. The goal is that this library will be cached and versioned from our CDN.

Yes, there's a small risk of a site having modified basic jQuery functionality. A very small risk. If you're restricting yourself to the core API (not plugins and such) I frankly don't think it's worth worrying about.

But if you're worried about that, then frankly I'd just use a slightly-modified jQuery hosted on your own CDN using a different symbol than jQuery (and not using $ at all). 31k vs. 15k in today's telecomms world is a non-issue; the primary cost will be in establishing the connection in the first place. If you wanted, you could probably pare that down a bit by removing parts you don't need, although sadly the jQuery internals are a bit of a morass and selectively removing functionality may not be trivial (depending on what functionality it is).

3
ded On

I'm one of the co-creators of Ender and I'll +1 Fazal's words.

A note on the Jeesh, albeit a nice starter-pack to Ender, the true power lies in the ability to extend Ender with its growing set of modules. You can check them out here: https://github.com/ender-js/Ender/wiki/Ender-package-list

Somehow, one way or another Ender became the forefront of "micro library" development, but really what we're after is putting a cohesive interface onto loosely coupled modules (however large or small they are). jQuery took a great first step in abstracting its selector engine (Sizzle), but unfortunately the rest of it is interdependent (dom, events, animation, ajax, utils, promises), thus making it impossible to pick and pull what you want.

On another aside, one of the neat things about Ender is the ability to publish modules to NPM and being able to port them into your project by name allowing you to build only what you need, when you need it

It's worth checking out the learn videos at http://enderjs.com/learn which will give you a better idea of how packages are authored, built, and consumed. You'll find that setting up Ender into your environment is extremely simple and actually quite fun to work with.

Let us (@ded or @fat) know if you have any questions and we'll be more than willing to help sort things out