Tuesday, April 8, 2014

Building single-page web applications

From looking at recent web frameworks like Angular.js and Ember.js, it seems like there's an emerging Right Way to build single-page web applications, which is different from the past Right Way to build web applications that relied on server-side HTML generation. In this post I'll try to outline the main ideas, so you can understand them without puzzling through some obscure syntax.

The main idea is that the client code keeps a "model" of the current state of the application, which is basically a big data structure. That model gets updated by user actions or sending AJAX requests for more data. A client-side templating library receives the model as an input, renders the HTML, and updates the HTML whenever the model changes. Apart from that, the client code never touches any DOM elements directly. The only way to update the HTML is to update the model and let the templating library do its job.

Ideally you'd have a main template which includes many smaller templates, and the templating library would figure out which parts of the model changed since last time. That way the client code doesn't need to care about incremental updating, because full updates are cheap anyway.

For handling events, like clicks, every template should be able to have a "controller" object in client code, and have special syntax for binding the methods of that object as event handlers on specific elements. I won't say much more about the organization of client code, because it doesn't seem to be quite settled yet.

The nice thing about that approach is that the client code no longer needs to use things like document.getElementById, element.className, or element.addEventListener. By using the templating library as the only way to communicate between the client code and the HTML, you eliminate most of the feeling of "brittleness". And since the templating library's only job is to render the model, which is basically a struct that can contain other structs, you don't need many fancy features in the templating library either.

If you like static typing, note that the model can use a structured type definition, like Google's Protocol Buffers. That way you can typecheck the client code that updates the model (if it's written in a statically typed language that compiles to JavaScript), the templates that render the model, and the bindings between templates and their controllers. Of course it would make sense to use the same structured types for communicating with the server as well.

To support animations and repainting, the templating library can allow you to set an optional "key" attribute on any element, to indicate that the identity of the DOM element should stay the same from one repainting to the next. That way you can use ordinary CSS transitions on elements, and they will work as expected. More complex animations should be done explicitly, by representing the intermediate states of the animation within the model.

There are many more topics to cover (human-readable URLs, authentication, i18n, logging...) but it seems like the approach can accommodate them without much trouble.

No comments:

Post a Comment