There are a lot of JS frameworks out there. Why are there so many, and how did we get here? How are they all related?
These big companies sat down and agreed on a way forward... just kidding, they didn't, they spend the next decade fighting for their own versions instead. They finally came together in 2009 and agreed on ECMAScript 5. Now TC39 agree on standards in June every year, with ES2018 being the most recent.
We'll come back to how important these new, fast moving, standards became, but first: while the web went from academic tool to a utility in everyone's homes, JS was a stagnant mess of competing versions.
The first JS wars: Platforms
Spoiler: the winner of this 'war' was jQuery.
Roll back to the early 00's and the browser landscape was a tough platform to develop for. No modules, no components (unless you count IE's behaviours), inconsistent DOM, inconsistent events - anything richly interactive probably meant Flash (and ActionScript).
There were two basic things that most developers wanted:
- Code portability: consistent JS that runs on IE, Netscape, Opera, Safari and so on
- Components: write a date picker once, then reuse it. Or maybe even use someone else's off the shelf
A JS library from this period would give developers a standard interface to develop on, and add a set of conventions for writing components.
The cost was that all that standardisation took lots of code - loading multiple frameworks was slow and most were incompatible with each other.
There could only be one!
While there were plenty of these frameworks (including, but not limited to Script.aculo.us, Prototype, MooTools, Dojo, Underscore, Yahoo UI and jQuery) once one had market dominance, and most of the components relied on it rather than any of the others, victory was assured.
It was quite a victory, as for a few years jQuery was so universal that many regarded jQuery and JS as the same thing. But that wasn't the whole story...
jQuery is just a platform - a bunch of standard tools for DOM manipulation and events. There were other things developers wanted:
- Consistent patterns for building entire applications
- Reusable HTML with data-binding
- Routing and state management
jQuery didn't really help with these, but lots of other frameworks did.
There were also library frameworks, like Twitter's Bootstrap, that gave you a bunch of basic components and consistent styles built on top of jQuery. A lot of these had built up over time, so you might have jQuery with jsRender and Bootstrap all together to build an app.
You'd have JS code to get an item (say a product on your site, called the model), a JS framework to render it (with HTML and data-binding, called the view) and some way to join it all up. Maybe Model View Controller (MVC) or Model View Presentation (MVP) or... let's just call them Model View something, or MV*. You can compare lots of them easily at Todo MVC.
Then Node.js happened.
The Age of JS tools
Most IDEs and developer tools were desktop applications, often written in languages like C++ or Java. The number of developers who worked in JS every day and had the skills and time to write desktop tools was fairly small. Most of the tools that were there (such as GWT, Bridge.NET and CoffeeScript) tended to be about desktop-to-web (transpiling Java, C# and Ruby/Python respectively into JS).
Node.js changed all that - suddenly it was easy for developers who write JS all day to also write their tools in JS. This accessibility meant there was an explosion of new tools and new frameworks to take advantage of them.
In particular these tools eroded the need for a platform JS library: instead of writing on top of jQuery (with every user needing a copy of it), you could rely on Babel or TypeScript to turn your code into something older browsers could still run. Packagers like Browserify, WebPack or RollupJS could bundle and process your JS files to send your users just what they need and no more.
Arguably, the winner of this period was React. React provides the reusable HTML and data-binding in an embedded mix of HTML and JS called JSX, and uses Node-based tools to turn that into plain JS that works with an extremely fast copy of the page called the Virtual DOM (or VDOM). There's easily a whole blog post into the details, but compared to the older template libraries React is fast, and with JSX it's easy to write.
The latest evolution of this approach are systems like Stencil JS where everything is compiled by JS build tools to plain JS, with no client-side framework at all. Many frameworks now include Node-based command line tools that build the final JS.
Finally, npm and Bower emerged, making it easy to download and maintain components. Unfortunately they don't actually help get the files into your JS app, so you'd need a module importer like AMD, SystemJS or CommonJS/RequireJS to do that bit.
Forks, Fractures and Opinionated Frameworks
Without the need for all modules to rely on a single framework, and most frameworks having enough of a component store to be viable, the pressure for one framework to rule them all had gone.
React originally had problematic license, not every developer wanted to be dependent on Facebook's IP. It was also fairly opinionated - it does some things in its own way (not bad or good, just idiosyncratic) that meant it doesn't always play nice with others. Competitors arose that used the same VDOM ideas like Preact, Inferno and Vue.js (Vue.js also skips the dependence on JSX).
React (and most VDOM frameworks) doesn't do everything, so gets combined with other frameworks that provide the rest of the application, such as Redux for state management or RxJS for reactive events.
Bower lost the fight of the package managers, which was unfortunate because (while is it faster) npm is designed for desktop Node projects. In the web, an additional step is required to flatten and resolve a single version of each module. npm doesn't do that, so wrappers like Yarn are required.
Even Node.js fractured, with inventor Ryan Dahl leaving and creating Deno.
The Evolution Of JS
While all this was happening, IE lost its market dominance, the ECMA deadlock broke and the JS standards started moving again. Competition meant browsers needed to get better to keep market share, and unlike the browser wars of the 90's (
<marquee> anyone?) this time the push was for faster JS and features all the browsers could support (mostly). New feature releases became annual and stopped using version numbers, so after ES5 and ES6 we switched to ES2016, ES2017 and so on.
These features are game changers:
- Component/module support:
- Web Components add a standard way to register a reusable control - no more competing framework-dependent way to register them
- ES6 Module imports add a standard way to import JS modules (and now have near universal support)
- Shadow DOM - isolate controls from each other
- Slots API to add content to a web component
<template>to create fast reusuable DOM fragements
- Literal iterpolated string functions
- Service Workers allow web applications to run offline and work like native apps
- HTTP/2 for push and pipelined requests
- Consistent API like
- Asynchronous support with
- Web Assembly for high performance
Google started Polymer to push for some of these features (in particular web components and Shadow DOM) to help use them and shim those that aren't supported yet. Other web component helpers include Skate.js.
VDOM doesn’t have native support (and probably never will) but React's latest improvement takes advantage of new asynchronous functionality to make it seamlessly fast.
Mobile is now how most people interact with the internet. Your web application working well on mobile is increasingly critical.
Mobile devices have intermittent, slow connections and a lot less processing power. JS is disproportionately expensive. For a long time, native mobile apps were seen as the only solution to this. In 2012 the norm would have been isolated web and native mobile experiences.
AMP is a minimal subset of functionality. It's limited, but guaranteed to load fast on mobile. Google prioritises AMP results in search, making it a good option for content websites (such as news).
Another option is to use new features like service workers, to progressively download rich functionality. Progressive Web Apps (PWA) can do almost everything native apps can, without the install overhead. You have to design apps with the mobile target in mind, using the PRPL pattern or something similar.
For a good example of PWA, check out Twitter Lite.
Where are we now?
There are so many frameworks because there can be so many frameworks. JS frameworks are specialised, portable, and often interchangeable. Don't stress about picking the wrong framework - you can always (and almost certainly will) change it later. The goalposts are moving, and the market in 2009 was very different from 2019.
Which frameworks should you learn? As many as you want; just make sure that you understand the underlying JS. For instance, if you use React learn how VDOM works, learn what JSX is transpiled to and what compromises/benefits there are to the approach. Learning the underlying mechanics won't always help you finish your project sooner or make it better, but it will always lead to you being more capable in the future.