Several months ago I started work on a new project that required a web-based user-interface. I had been out of the HTML game for several years, spending time instead on Windows Forms and Flex-based applications. For this new web project, however, I wanted to retain some of the user-experience and development features that I came to enjoy working with traditional "thick-client" technologies.
My investigations led me to discover a technique now called the JavaScript "Single Page Application," or SPA for short. I am no stranger to some of the paradigms of a SPA having spent the first ten years of my career developing web apps with rich user-interfaces that used AJAX-like techniques before AJAX was even a term. But SPAs have evolved way beyond simple AJAX calls and the now clunky-feeling ASP.NET "Update Panel." The architecture of a SPA more closely resembles that of full-blown client-server apps written in traditional technologies like Windows Forms, bringing with it a more developer-friendly environment and a better end-user experience. For that I think we can thank Google Chrome for stepping up the browser wars and resulting in a doubling of JavaScript performance every nine months over the past five years or so.
After much research (including much material from John Papa), I began to develop my own SPA framework to serve the needs of my project. Keep in mind that a SPA relies on a single HTML page as the application container and the browser makes no further full-page HTTP requests once that page is loaded. Instead, the SPA loads and renders content on-demand as it is required. To make this happen, the SPA has to perform much of the work that has traditionally been performed by the web server, such as view routing and data-binding. While SPAs as an all-inclusive framework are fairly new, many of the functions it must perform are available in the form of individual JavaScript libraries, some of which have been around for years.
And so, I set out to assemble my own framework using several of these individual libraries. In the meantime, and months after I began my own efforts, a wholy-inclusive SPA platform has become available called Durandal. Though I had my own framework mostly developed by this point I wanted to see what Durandal offered and how it compared to the features I had put in my own framework. To my surprise, the two frameworks were amazingly similar. This is most likely because the problem domain was identical, and many of the libraries Durandal uses are the same ones I chose:
- jQuery for DOM manipulation. This is a no-brainer for me, though there are reasons to choose other DOM frameworks.
- SammyJS for in-page "hash"-style routing. I have also implemented routing using Path.js.
- RequireJS for dynamic on-demand loading of resources, whether it's HTML, JavaScript, CSS, or localization resources.
- Knockout for data-binding. This is turning out to be a pretty core piece of the developer experience since it abstracts away a lot of old-world direct DOM manipulation for form input values and label display.
While all these libraries (and many more ancillary libraries I haven't mentioned) are important in assembling a SPA framework, they don't solve the entire problem. While a routing library helps with determining the view the user wants to see, it doesn't actually help with view management per-se. So I developed a view framework where each view has an event lifecycle: initialize(), beforeShow(), show(), hide(), afterHide(). Not surprisingly, Durandal offers a similar view lifecycle. What appears to be missing from the Durandal framework (though, honestly, I haven't spent more than a few hours examining it) is an integrated user-authentication mechanism, as well as global error handling and the ubiquitous "404" handling for undefined view routes.
If I had to do it over again, I would definitely pick the Durandal framework, however. Their JavaScript-foo is at least an order-of-magnitude better than mine and Durandal is already beginning to accumulate a large community of developers who are using it. This can only mean the product will continue to evolve and grow with a large user base reporting and fixing bugs, making it far more robust than any feeble framework I could manage to tack together. Still, it was gratifying to see that I, a self-proclaimed "hack," was able to assemble a SPA framework that performed many of the tasks Durandal does (though undoubtedly not nearly as well), and maybe even one or two that it doesn't. And it sure is a blast to be back in the web world again. :-)