Posted on by & filed under Content - Highlights and Reviews, Programming & Development.

A guest post by Matthew Beale, a web developer based in Brooklyn, New York. He is a JavaScript consultant and has contributed to projects such as: Ember.js, Ember-Data, SeedFu, and Facebooker.

The single-page application framework Ember.js promises a lot of functionality. It helps developers manage DOM, events, URLs, objects, asynchronicity, and state. The completeness Ember aims for has an unavoidable impact on file-size, and a production build checks in at 981K (236K minified, 66K gzipped). There are many arguments as to why this initial sticker shock isn’t as bad as it first seems.

Regardless, at times file-size is going to be more important than features.

There are several dependencies for Ember.js beyond jQuery (which is expected at runtime). With the exception of Handlebars, these lesser-know dependencies are built into releases of Ember. Without Ember, they are à la carte feature libraries. They are held to the same high standard as Ember itself, are well-tested, and receive attention from the core team and community of Ember.js developers.

If Ember is too heavy for a project, don’t throw the baby out with the bathwater. These small libraries can be used in Node.js (where appropriate) or mixed into AngularJS and Backbone apps. None of them require you to use Ember itself. In fact besides router.js, none of them have any dependencies at all. These are small, focused tools with a smart team of developers behind them:

RSVP.js

“Specifically, it is a tiny implementation of Promises/A+ and a mixin for turning objects into event targets.”

Promises are probably the best pattern for managing asynchronous code available to JavaScript developers today. They are compelling enough that ES6 will likely be adding them to the language itself. A promise represents an unresolved state. When you resolve the promise, the state becomes successfully fulfilled and the success handler is called. When you reject a promise, the state becomes un-fulfilled and the failure handler is called. Promises replace callback and event patterns for functions that have success and failure results. “Promise/A+ refers to a unified promise spec, of which RSVP is just one implementation.”

Here is a simple usage of RSVP:

A defining feature of promises is that they are chain-able:

Beyond the basics of promises, RSVP has a few useful extras:

  • RSVP.all([promiseA, promiseB]) will resolve with an array of values when all the promises have resolved.
  • RSVP.hash({first: promiseA, second: promiseB}) will resolve with an object of values when all the promises have been resolved.
  • RSVP.resolve() and RSVP.reject() return thennables already in their respective fulfillment states.
  • RSVP.defer() returns a jQuery-style deferred, which you can call resolve or reject on.
  • RSVP.denotify(fnWithCallback) wraps a function that expects a success callback as the last argument in a thennable.

Beyond promises, RSVP also provides a mixin for objects that allows an event fired with obj.trigger('myEvent') to be caught with obj.on('myEvent').

RSVP.js is 17K – 6.4K when minified and 2.4K gzipped.

Router.js

Router.js manages the configuration of a single-page app as the user moves from route to route. It is built upon route-recognizer.js (included in the build) and RSVP.js (which is a runtime dependency). Router.js does not know how to use the HTML5 history API, the pushState API or anything about the browser’s URL. Used without Ember, you’ll need to wire up the browser’s location by hand.

At it’s core, Router.js maps URL strings to handlers. Handlers run several callbacks when being loaded, and respond to events when being entered or exited:

Ember developers will recognize this API as very similar to what they normally use.

Router.js is 41K – 21K minified and 5.1K gzipped. The route-recognizer.js micro-lib is built-in, but Router.js requires RSVP.js at runtime.

Handlebars.js

Handlebars.js is a fantastic templating language for JavaScript. It encourages simple and logic-free templates, but does not enforce the idea to the point of pain. Handlebars templates must be compiled, and in production this will often happen as part of the asset compilation pipeline.

Ember developers are most familiar with the Ember.Handlebars varient of Handlebars. The raw syntax, free of Ember’s additions, is actually much simpler.

The templates are compiled into functions, which can be called with a context argument. Custom helpers are easy to define:

Even with Ember apps, the raw Handlebars API can often be useful. I’ve used it as a language for email templates, and to allow theming of webpage HTML. Using Handlebars with Backbone is trivial, and the mature ecosystem around Handlebars and Ember virtually guarantees there is a server-side template compilation option for your build pipeline.

Emblem.js is a templating syntax built on top of Handlebars, and is more similar to Haml or Slim while still compiling to a Handlebars template.

Handlebars in its entirety is 71K – 39K minified and 12K gzipped. The compiler portion of the code, however, is often not required on the client-side. The runtime, which is all that is needed to run a template, is only 12K (5.8K minified and 2.6K gzipped). Handlebars.js has no dependencies.

Metamorph.js

Metamorph.js provides an API for creating and updating arbitrary HTML snippets. With metamorph.js, this arbitrary HTML does not need to be enclosed within an HTML tag:

In Ember.js, metamorphs power data-bindings to templates. Alone, metamorph.js is 15K (6.6K minified, 1.9K gzipped). It has no dependencies (not even jQuery).

Backburner.js

Backburner.js provides a runloop (sometimes called an event loop) for JavaScript. A runloop is ideal for any application architecture that must render a user interface and react to events that cause that interface to be updated. They provide an elegant way to batch rendering of the UI, regardless of how many individual parts of application logic ask for a redraw of the interface.

For instance, in this example from the Backburner readme, #name will only update its text once:

Each time setName is called, updateName is scheduled to be run once in the “render” queue. Name can be set and reset within the runloop and only the final value will land in DOM.

Any expensive activities that can be batched are a good candidate for using a runloop. DOM updates and persistence are good examples. Backburner.js is 17K (10K minified, 2.5K gzipped) and has no dependencies.

Conclusion

Ember’s aim of completeness provides an opportunity to discover good abstractions. Minimal frameworks are useful in specific situations, but they don’t encourage the kind of collaboration and deep thought on hard problems found in the Ember community. For your next file-size focused project, look to the tools used by the big guys for a solid base.

Be sure to look at the Ember.js resources that you can find in Safari Books Online.

Not a subscriber? Sign up for a free trial.

Safari Books Online has the content you need

Developing an Ember.js Edge will take the reader from a casual interest in Ember.js through to building a complete application. Along the way we’ll cover the current state of client-side web development, the history and evolution of Ember, and the projects and challenges that have informed its design. Then we’ll dig deep into each of Ember’s constituent component libraries, demonstrating how each operates on its own and how they work together harmoniously as a framework.
Instant Ember.js Application Development How-to is a practical guide that provides you with clear step-by-step examples. The in-depth examples take into account the key concepts and give you a solid foundation to expand your knowledge and your skills. That will help you use the power of Ember.JS in your applications.

About the author

matt.beale Matthew Beale is a web developer based in Brooklyn, New York. He is a JavaScript consultant and has contributed to projects such as: Ember.js, Ember-Data, SeedFu, and Facebooker, who can be reached at @mixonic.

Tags: backburner.js, Ember.js, Handlebars.js, jQuery, metamorph.js, Node.js, rout-recognizer.js, Router.js, RSVP.js,

One Response to “Ember.js, À La Carte: Examining Feature Libraries”

  1. Mohamed Cherif BOUCHELAGHEM

    Hi, I think canjs.com is perfect alternatif mustache/handlebars observable, routing; deferred models, compute, control is the kind of the framework where you start small and scale later