The phrase “single-page application” has come, over the years, to mean both a particular type of website and a web development paradigm. A website could be considered a single-page application (SPA) when it is built to resemble a desktop application more than a traditional static web document, taking advantage of structured Javascript to connect to server-side services that add smoothness and dynamicity to your average web experience.
That means sites where users can both read and edit the content, and content itself is updated without a page refreshing. Think Gmail or Twitter.
The phrase itself has roots that stretch back to 2002 when a few engineers from Tibco Software actually patented the technique behind an early attempt at a single page application. It was around that same time that Slashdotslash.com came on the scene, one of the first web applications online, a sandbox for experimenting with new web technologies all in a single HTML document without having to refresh the page.
But things really kicked off for SPAs in 2008, when Jesse James Garett gave a name to AJAX, a technique that allowed developers to make dynamic requests to the server without loading a new page.
This timed rather organically with the rise of client-side frameworks like jQuery, Dojo, and Prototype, raising the profile of Javascript and stretching its limits.
Without these two trends, it’s unlikely that we would see the emergence of new single-page application frameworks, inspired by the likes of jQuery, but tweaked to take advantage of AJAX.
And if you search around enough you’ll see plenty of articles that dive deep into the technical considerations of one framework versus another, answering the question of how it does what it does best.
So, I thought it might be fun to take a look at how developers described their own frameworks, at their conception or early on in its development, to try and glimpse the intentions behind them.
What will become abundantly clear is that each framework is a game of trade-offs. The ideology behind these frameworks plays heavily into the decisions made about how they would be structured, their programmatic API, and the footprint they leave behind.
Please keep in mind that this is in no way a comprehensive list, but I think it represents the trajectory of frameworks fairly well.
Backbone.js aims to provide the common foundation that data-rich web applications with ambitious interfaces require — while very deliberately avoiding painting you into a corner by making any decisions that you’re better equipped to make yourself. — Backbone.js documentation
Backbone.js is probably where any conversation about SPA frameworks should start. It was developed by Jeremy Ashkenas in 2010 and aimed to give structure to what had become an unruly Javascript application landscape.
Ashkenas built Backbone on top of existing libraries, namely jQuery and Underscores. That’s where the idea for a “common foundation” comes from. The goal of Backbone was to unify and organize complex Javascript code in a way that made it reusable across projects and simpler to understand. So Backbone provides just enough structure to move programmer away from unwieldy “spaghetti code” and deal consistently with data on the server, but still leaves the bulk of decision making in the hands of individual developers.
I wanted to see if I could simplify this. But I didn’t want to simplify it for a developer, I wanted to simplify it for web designers. So people who don’t know how to program. And because people don’t know how to program, I had to be constrained to HTML. — Talk by Angular creator Miško Hevery
AngularJS hit the scene right around the same time as Backbone, though it had been in development for some time before that. The intentions behind Angular were crystal clear. The target audience for the framework was designers, or at the very least, inexperienced developers. Most of the decisions about how the framework’s structure followed from this assumption.
Templates, for examples, could be created right in plain old HTML so that Angular users didn’t have to learn something new to get started. Angular also came with a few handy tools built right in, and encouraged an opinionated approach to development. All of this made the actual size and breadth of Angular much larger than frameworks that had come before it (like Backbone) but it also took the learning curve way down.
Ember is a JavaScript framework that does all of the heavy lifting that you’d normally have to do by hand. There are tasks that are common to every web app; Ember does those things for you, so you can focus on building killer features and UI. — Original Ember Readme
Ember actually began as a rewrite of the web framework SproutCore, which had been popular around the time of Backbone and Angular, and was used by Apple on many of their web projects. But SproutCore languished a bit after 2012, and many developers recognized that it was time for change. So developers Yehuda Katz and Tom Dale began working on SproutCore 2.0, which became Amber.js, and eventually Ember.
Katz and Dale had a lot of experience in the Ruby on Rails community. For those unfamiliar, Rails is a server-side framework that prefers “convention over configuration.” This basically means that many decisions about how an application should be developed are already made by the framework giving individual developers a good head start.
This spirit informed the approach that Ember took. Ember’s creators reasoned that there was a whole lot of boilerplate code (getting data from a server, connecting routes to templates, breaking things out into partials, etc.) that developers needed to write over and over again for every project. So it did this work right up front, making a lot of assumptions about how the code works and abstracting it away.
As long as you stuck to Ember’s prescribed approach, a lot is done for you before you even write a single line of code. Katz even bragged that “if you’re a Backbone fan, I think you’ll love how little code you need to write with Amber.”
React is a library for building composable user interfaces. It encourages the creation of reusable UI components which present data that changes over time.
When React first launched, that’s how its developers described it. But they really summed it up like this:
React really shines when your data changes over time.
React was created at Facebook to solve one very specific problem. When data is constantly changing and updating on a page (like with live updates stream in), things tend to get a bit slow. So they isolated the layer that was causing this problem, often referred to as the view layer, and went to work.
So for React, the why was simple. Speed.
Unsurprisingly, React is a framework in which all things follow from the data. When the data changes, things respond.
Quickly.
There are all sorts of algorithms (virtual dom anyone?) and even a new markup language named JSX that underpin the effort, but at the root, data is a first-class citizen. And as it turns out, speed not only gave React developers a clear goal to aim for but also a principle to benchmark against.
Vue.js is a library for building web interfaces. Together with some other tools you can also call it a “framework”, although it’s more like a set of optional tools that work together really well. — Evan You, “Vue.js: a (re)introduction”
Vue, in many ways, began as a reaction (pardon the pun) to React. Creator Evan You recognized the advancements that React was able to make, but at the same time saw a community that was fractured and ever in flux (last one, I promise).
You initially resisted the name “framework” because he wanted Vue to be something that provided only the bare minimum out of the box. But to try and limit the splintering of the Vue community, You put a lot of efforts into modular, first party add-ons for the main Vue codebase. It blended the more prescriptive approach of frameworks like Angular and the flexibility of libraries like React to create a disparate set of tools that happen to work really well together.
For me, I wanted the developer experience [of React], I just didn’t want to pay for it. So that got me thinking.– Jason Miller, Putting the “P” in Preact
Preact actually started out as a Codepen way back in 2015, a way for Jason Miller to experiment with some of the rendering limitations of React. But it didn’t truly come into focus until a few performance benchmarks were published online demonstrating the sluggishness of React on mobile devices, benchmarks that Miller’s quick and dirty experiment improved on greatly. So he released the code as the open source library Preact.
The stated goal of Preact has always been exactly above — all of the niceties of working with React with less of a performance cost (hence Preact). Since then, the library has been updated and retooled on more than one occasion, but it has always kept that purpose in the foreground, making use of React’s API’s while simultaneously making changes to the way it works behind the scenes.
Hyperapp is a modern JavaScript library for building fast and feature-rich applications in the browser. It’s the smallest out there (1.4 kB), it’s simple, and fun to use. — Jorge Bucaran, Introducing Hyperapp 1.0
“Small” is certainly the operative word for Hyperapp (originally called Flea). The codebase initially clocked in at around 4KB, but by the time of it’s 1.0 release, that number dropped down even more. Hyperapp gives you just the basics, a way of managing state and templates in your code, but its goal is to mostly provide a few tools and get out of the way. From the beginning, Bucaran has always emphasized the Hyperapp’s footprint and pragmatic approach as it’s foundational principles.
If there’s a lesson learned here, it’s that perspective that guides frameworks. Its design, its architecture, even the problem it is trying to solve follows from this perspective and sets a tone. From there, a community gathers around this perspective and catalyzes its efforts, and after a bit of a time, a new framework is born.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.