Picking a Javascript Framework in 2015

June 8, 2015
This is a follow-up to my previous article regarding our decision to stop using YUI Library and find a replacement. In this article, I look at the current state of Javascript frameworks and assess how well they meet our needs. Ultimately I find them all insufficient as a core foundation, and suggest that we build a new foundation which embraces our criteria.

In a previous post I described our past experience with Javascript. I explained that we have been using the YUI Library since 2006 with mostly positive results. But it is 2015 and much has changed. We are looking for a replacement. 

There are many libraries out there to choose from, with many of them focused on different, but overlapping, aspects of development:

  • jQuery is the clear popular favorite for making dynamic web easier.
  • AngularJS has been a leading choice for "serious javascript developers".
  • More recently, React has gotten tons of attention. 
  • ES6 (ECMAScript 6) is near completion.
  • And a plethora of other frameworks claim various benefits of their own.

In this post, I examine the key factors we have identified for deciding a framework in 2015, how these are very different than they were in 2006, and look at how well the various frameworks available now address these needs. Finally, I decide on a path to move forward on which I believe will provide the ideal foundation for web and other Javascript based projects for the next several years.

Why Not Just Choose jQuery?

Many developers don't feel the need to put much time into picking a framework. Many already know jQuery; they like jQuery; and everyone else seems to be using it. And indeed, popularity is a positive factor that should go into the decision. But the base framework choice has many repercussions, so a full analysis should be done with a clear and quantified view of the benefits popularity offers. And those benefits must be weighed alongside many other important factors.

jQuery is currently in use in about 60%+ of the leading sites—a lead so strong that few developers could even name the #2 library. jQuery is essentially the de facto library to load when embarking upon a new web project (much respect to the jQuery author John Resig for this accomplishment!). Most javascript developers know how to use the library, and the number of "plugins" available is extensive.

jQuery Pros

With so many developers rallying alongside jQuery, you will benefit in the following ways:
  • Its used extensively, so you know browser coverage will be vast, and bugs will be few and far between. Bugs that do exist will be well documented.
  • Lots of information and help available on the Internet (and in books, classes, etc.)
  • Tons of "plugins" that work with or may even require jQuery.
  • Well written and clearly organized documentation. Both API and usage tips are together on a single page, making it fast and easy to search and read.
  • The distribution files are readily available on CDN servers for fast, local loading - and in many cases may be cached by the user's browser already.
  • If/When you bring others in to work on code, they will likely already know jQuery.

These are some of the benefits of jQuery over other libraries that we can list without even considering the actual features of the framework itself. It would seem hard for any other library to compete.

But I feel there are some choices made by the jQuery authors, often due to the time period in which they were made, which makes jQuery a poor choice in 2015. As the framework name indicates, jQuery focused first on finding DOM elements on a web page. It has many functions to then inspect and change those elements. This focus is no longer relevant. In fact, in 2015, one has the same power of selection built in to every modern browser.

There are many other problems I could identify with jQuery, but rather than list specific jQuery cons, lets itemize the objectives we wish to achieve with a framework and consider how well the jQuery framework, or others, meets those objectives.

Framework Objectives

Some of the most important objectives that need to be considered are iterated below. The relative importance of these will vary by team and by project. But they are the major criteria which we are using to pick our framework.

I hope to make it clear that for any project larger than a simple website, features play a very small role, and that its much more about providing a foundation upon which a developer or team can build upon.

Basic Architecture

The architecture of a framework is very important. It strongly effects, and often even dictates how you must structure the apps that you write on top of it.

One of the pains of using YUI Library was that it was a large monolithic framework. YUI was written in modules, but to swap out one piece of functionality provided by YUI with a third party implementation was difficult at best. They were designed to be a tight-knit group. 

jQuery is also quite monolithic in its approach. It is not written in modules - but delivered as one large module. Don't like jQuery's animation handling (and you'd be right not to)? Well, you get it anyway - and then you must monkey patch a better animation engine over it.

Given the diversity of applications being written for the web, and the variety of contexts they are deployed into - we are better served with a thinner and more interoperable base layer. The term framework already evokes a structure which encompasses your entire application, rather than simply providing a foundation upon which you can combine best-fit 3rd party modules to create the ideal surface upon which to build your apps. 

Coding Style / Philosophy

Somewhat related to the basic architecture is the coding style. YUI used a very academic approach, while jQuery is nearly the opposite. By academic I mean YUI resembled a more classic Object Oriented style - using deep inheritance hierarchies and get/set object properties. jQuery, by contrast takes a very terse approach - even using the same method for different functionality based on the arguments.

I believe that neither quite got it right. Brevity is good and flatter hierarchies is preferred - but overloading functions is a bad idea. The ideal framework would find a better balance between these two extremes.

Browser First vs. Context Agnosticism

In 2006 when jQuery (and YUI) were first released, the browser was the only context these libraries were meant to be run in. jQuery is named after its primary original goal, which was to make it easier to find elements within a page (and then do something with them).

In 2015 javascript is being used in many other places outside the web browser: on the server, as a scripting language within other applications, for OS scripting, within database engines and as standalone user applications. In many of these non-browser contexts there is no need for DOM-related functionality.

So ideally, the best foundation core would be absent of browser-specific code. The browser related functionality would then be an optional extension (see section below on Loadable Modules). Furthermore, the browser module should take advantage of the state of browsers in 2015 and their mostly consistent, rich API. Older libraries like jQuery have difficulty transitioning to this approach due to the need for backward compatibility.

Promise Based

Complex web applications often contain a lot of asynchronicity.  They are loading data over the wire, reacting to user events, firing animations once images load, etc. This juggling of events, callbacks and error handling quickly lead to what is referred to as Callback Hell. When you depend on many asynchronous activities in your application, the callback management challenges have even given rise to libraries to help, such as the async library. 

Promises go a long way in making asynchronous code cleaner and less brittle. Promises are now available in nearly all the modern browsers and are a standard part of ES6. (Unfortunately, not available in IE11). But to maximize the benefits of promises, it helps if all asynchronous functions use them. This enables chaining as well as other strategies that group or schedule events and callbacks. 

So for choosing a framework in 2015, the asynchronous functionality should be promise based.

Currently, jQuery offers a promise-like utility called Deferred . But this is not fully compatible with Promises and is therefor substantially less useful.  YUI has a module for ES6 compatible promises, but these were not used in the core library anywhere.

Of course, there are many stand-alone implementations of Promises that can be added to your solutions. You can then "promise-ify" any functions you call that are using deferreds or callbacks. But this adds bulk and overhead to an already complex code path, which is what we are trying to avoid in the first place.

So to reiterate: Promises should be both included and used internally throughout any framework worthy of consideration in 2015.

Module Loaders and Builds

This is a big topic that deserves its own article - but it is important to recognize that the architecture of the core framework plays a big role in how you break your project into modules and build your applications for deployment.

If you wish to break your application into many small modules (as you should), you will need to determine how you will build those modules into a deployable application. 

jQuery doesn't have a standard concept of modules or a module loader - it is offered as one big function called jQuery (and aliased to $). [Note: jQuery does have a getScript() function to dynamically load and execute javascript, but getScript() has no concept of dependencies and isn't a full fledged module loader]

YUI Library was distributed as a bunch of smaller files which could be appended together by an external build system, or loaded dynamically as needed. One could also combine these techniques to load a core set of modules in a single request, and then load additional modules if and when needed dynamically.  This was a very effective and efficient approach, which could be used in your own modules as well.

There are several standalone "module loaders" such as RequireJS which provide dynamic loading similar to YUI.  And there are build-time solutions such as browserify which gather modules and their dependencies into a single file for distribution. These can be used with jQuery, or other frameworks, to dynamically load your own modules.

But in order for the framework itself to take advantage of dynamic module loading (i.e. its own modules), it has to provide one itself. The YUI Library got this part right (though given its overly-academic approach it became a challenge to identify which modules of the many available were required for a build).

Ideally, a framework should adopt a module format and offer a built-in loader to provide a dynamic load option for both the framework itself, and as an option for user modules. The built-in loader should be thin enough that if end users prefer an alternate approach for their own modules, they aren't burdened with two large competing module loaders.

What about Features?

So we haven't talked much about specific features. This has been more about architecture, philosophy and internals. The reason for this is that specific features are not nearly as important. I don't care if a framework provides a good charting feature, or calendar, or even animation. These needs are all served in various feature-specific libraries. Those library authors have increasingly rejected dependencies on jQuery or any other framework so that they will work in any environment. 

This is why it is much more important to have a rock solid foundation that provides and encourages efficient and modular coding practices. This way you can build complex and highly dynamic applications that can make use of best-fit libraries for specific features.

Of course, the very commonly used features such as element selection, domready, ajax, etc. should be easy to include. I'm not suggesting that a developer should have to hunt around for every little need they have while building a solution.

But again, in 2015 many of these features are built-in. Check out vanilla-js.com for a humorous but informative look at built-in browser functionality as if it were a competing framework. (No matter what features you choose to include, the resulting "library" is 0 bytes!)

So unless you need to support very old browsers (I'm looking at you IE6), you might not need jQuery or any other framework for the basic features.

What About Data Binding / Angular / React?

As the complexity of an application and its interface grows, so do the challenges of ensuring a consistent and updated state of your UI. Most developers eventually realize the benefits of keeping a clean separation of the business logic/data (model) and the user interface (view). This is generally referred to as MVC (Model-View-Controller) or an alternate (MV*).

Several high profile frameworks have risen to aid in building applications in this pattern. Google's AngularJS and Facebook's React are two of the most popular right now. These and other MV* frameworks are very much worth consideration - particularly if your "web site" behaves more like a "web application".

These can completely replace a browser library like jQuery, or they can sit atop it. Angular, for example, contains a subcomponent they call jqLite which is optionally included if the full "jQuery" is not found. (Lots of potential gotcha's there!) React discourages any direct DOM inspection or manipulation. And so while you can still load jQuery, little of it will be used.

This awkward mix of loading redundant and/or unusable code is indicative of a badly structured approach. Others clearly agree. Angular contains its own module loader - but using that for your web applications means learning a different module loader for your non-Angular sites. Likewise, if your jQuery/RequireJS site evolves into needing data binding, you face the choice to completely replace both libraries with Angular, or loading Angular on top of them and having lots of redundant code. This may be partly responsible for average web pages now clocking in at over 2MB!

A much better approach that supports projects of all sizes and evolves smoothly, is to have module loading be part of the core - but DOM manipulation is not. The DOM functions can be optionally loaded, or a data binding framework can be used. Neither case carries a redundant code penalty or growing pains as you swap out components.

To reiterate, data binding should be an optional enhancement, not a core framework. When it is added to an existing solution, there should be very little overlap or redundant functionality.

Available Foundations that Meet Our Needs

Now that we've identified what a core foundational Javascript library should look like, what options exist that meet this criteria?

Well, here's a list of popular frameworks (alphabetically) and a brief note about why they do not qualify:

  • AngularJS - Too heavy handed - not a good fit for many project, so not a good general purpose foundation. See section above on data binding.
  • Backbone - A early popular data binding library. Could be used as extension, not a core foundation. Uses jQuery for DOM() if desired, which is problematic.
  • Bootstrap - Nice set of CSS classes for building modern websites, but doesn't address any of our needs. Also depends on jQuery for DOM functions.
  • Dojo Toolkit - Mostly the same problems that plaque jQuery. Dojo 2 sounds like they are moving much closer to our criteria - but still fairly monolithic (for legal reasons they claim?) and they are choosing Typescript as the core language, which means it must be transpiled into Javascript.
  • Ember - Large MVC package with templating, routing, etc. Definitely not the thin foundation we are looking for. Maybe useful for other purposes.
  • jQuery - Too monolithic, browser-centric, provides too much in "core", Not promise-based, offers crippled Promises, animation deeply flawed, no module concept.
  • MooTools - Mostly the same problems as jQuery. More modular, but still browser-centric, not Promise-based, etc.
  • React - Similar to Angular, this is not a good fit for many projects, and so not a foundation. Could be used in addition when features needed. See section above on data binding.
  • YUI Library - This is what we are using now. Read our previous post to see why it doesn't meet our current needs.
  • Zepto - This is a jQuery-compatible library written to be more compact, which I applaud. It suffers from all the same issues as jQuery, just with less bloat.

Building the Best Foundation

I have searched fairly extensively for a foundation that meets our needs and have come up empty. I believe there are others that recommend this approach - Chris Love in this Code Magazine article describes a similar strategy which he calls "Micro Javascript"—dynamically piecing together best-fit single-purpose micro libraries for efficient, high-performance apps.

I think Chris and I are championing the same approach; but it is very valuable to adopt a module style and load a foundation that understands and can load these modules. As a developer or development team, you will still want to choose specific single-purpose modules that you know how to use, keep available on your server or CDN, and can pull in to any project as needed. You will also likely write many of these yourself. 

Now you could use a fast, specification-compliant Promise library like Bluebird along with a popular module loader like RequireJS. That would give you a core foundation upon which you could then load any necessary single-purpose modules. I considered this option myself. But Bluebird is 72k minimized, and RequireJS is 15k minimized. That is 87k before you have loaded a single module! I would like to see these two functions provided in about 5k.

Of course, we could find smaller Promise implementations and smaller module loaders, but I chose these because they were very fast (bluebird) and provided enough features for complex sites (RequireJS). Things get prioritized in different ways for different teams - and apparently my priorities (small, fast, powerful, cleanly written, and well documented) is not as common as I'd like it to be. 

So I have decided that the best option is to write this foundation myself along with help from the web development community (you!). This may sound more ambitious than it really is. At the beginning, it is just writing a Promise implementation to spec, and a powerful but efficient module loader. In fact, I've already written the Promise implementation—its called Zousan. It is 2k minimized (less than 1k gzipped!) and its the fastest Promise implementation I know of. So we're off to a good start!

Stick Around for Joy

I will be moving quite quickly on this. The Promise portion is done, and the module loader is near completion. 

I will then identify the best single-purpose modules on Github, NPM, MicroJS, WWWhere, etc. to serve common needs. Where I can't find a module that meets my criteria, I will write it. My criteria is the same as listed on the Zousan doc:

  • Fast - I like code that is fast. I put users first, so a responsive, fluid UI is essential. I make heavy use of animation in my solutions and I even sometimes write games using web technologies. But regardless of the type of app you write, better performance is always better!
  • Small - Again, putting the end-user first means quickly loading your app. It means using less of their RAM and browser cache. This also plays friendly with smaller devices like phones and watches. Powerful can be a good thing, and sometimes that takes a bit of code, true. But redundancy, cruft, unneeded legacy support, or lots of unused features wastes a lot of time and resources. And unfortunately this is very prevalent in web frameworks and libraries.
  • Clearly Written and Documented - I like cleanly written code, with a good code/comments balance, reasonable variable naming, not-transpiled, and smart encapsulation. At some point you will likely need to dig into the source code of any modules you use very heavily, so it better be readable. And of course, to be usable you need good documentation. A lively community surrounding a project is useful, but it is not a substitute for documentation–and is much less necessary when code is easy to use and understand.
  • Simple Build - I prefer modules that are fairly self-contained without many dependancies. Make the build process clear and easy. Provide a pre-built minimized and non-minimized version of the module right in the project. Clearly describe where it is in the README. [Bonus Points: A link to a CDN version, such as here or here.]

We have quite a few modules written as extensions to the YUI Library (not open-sourced) and I will move those to work within our new foundation (and as stand-alone modules) - so there is lots of Javascript fun coming!

I invite everyone reading this to comment below about this plan and I hope you will follow as we build a practical and efficient foundation for Javascript projects in a 2015 mindset!


If you or your organization could use a somewhat fanatical developer on your current or next project, lets talk. I am passionate about the user experience, easy to work with, and I get stuff done. Lets build something great!


Picking a Javascript Framework in 2015 Tweet This!
Glenn is the founder of bluejava K.K., and has been providing consulting services and developing web/mobile applications for over 15 years. Glenn lives with his wife and two children in Fujisawa, Japan.
Comments
(Comments currently disabled)