Skip to content

Instantly share code, notes, and snippets.

@jedrichards
Last active December 31, 2015 01:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jedrichards/7916199 to your computer and use it in GitHub Desktop.
Save jedrichards/7916199 to your computer and use it in GitHub Desktop.
Marionette One Page Web Apps

Marionette One Page Web Apps

Essential Elements

A Grunt build process

  • General development is done on your unbuilt files
  • Set up a watch task to continually compile CSS
  • Don't attempt to build and optimise the entire site in a watch task, it'll take too long
  • When ready to deploy your site then compile/uglify/minify/concat into a dedicated 'build' folder

An AMD module loader

  • Use a module loader like RequireJS or curl.js to organise your project files into logical modules and automatically handle nested module dependencies
  • An AMD module loader exposes two global functions, require and define. The former loads in modules, and the latter defines modules
  • One module/file per view class for example
  • The module loader can also load in text based HTML templates as modules
  • Incorporate your module loader's optimisation tool into your build process to compress all your app modules into one JS file for serving in production
  • Only the top level module dependencies are considered in the dependency graph when the project is optimised, any further calls to require will not be incorporated into the built file by default and instead will load in modules async as encountered at runtime - this enables lazy loading
  • The AMD module loader will execute in runtime both on dev and on prod. On dev it will load in module files dynamically as needed, on prod it will just serve up direct in-memory references whenever a module is requested

An approach for accessing your API

  • If possible avoid loading JSON data into your app via CORS, it adds complexity to both front and backend code bases
  • If possible access your app via a nginx proxy, it should serve your app's static files as well as reverse proxy to your API so that your app can access API end points via requests to the same domain on a url something like /api/v1/endpoint
  • You can run an nginx proxy locally in your dev environment and on production to acheive similar results in both environments. Vagrant is nice for dealing with this on dev
  • If your backend system is also serving your frontend static files (e.g. Node Express, or Django etc.) then of course you don't need an nginx proxy

Configuring XmlHttpRequest requests

  • Gloabally configure your app's interaction with the API rather than indivdually in every interaction with the Backbone model layer
  • Its a good idea to try and generically handle failed requests and respond to the various HTTP error codes as part of this global setup too
  • jQuery's ajaxSetup, ajaxSend and ajaxError functions are great places to do this

App architecture considerations

  • Have an app wide "event bus", a mechanism to enable app wide communication via events
  • Marionette's Command and Request classes are good for this, and become a sort of distrubuted controller layer
  • Encapsulate re-usable business logic into these Commands
  • Views should only be concerned with listening and reacting to simple DOM events
  • Views can be bootstrapped with populated models by Commands before they're instantiated
  • Try and keep direct API communication and model manipulation outside of your views as much as possible. Having "Service" classes that handle all direct API interaction seems to work well
  • Make use of Backbone's pushState url routing feature, but don't treat it too much like a backend routing framework - remember unlike a backend app a JS app has persistent state, so try to leverage that and avoid using url changes as the primary navigation mechanism - you should be able to change your app's state without necessarily changing the url
  • If you plan to use pushState you'll need some extra nginx url rewriting rules to ensure your app's index page is always served no matter the requested path

Marionette view Classes

  • ItemView Represents a single item. Either a single member of some list, or some individual component on your page
  • CollectionView Represents a collection of ItemViews. Doesn't have any surrounding HTML structure apart from a single wrapping element, e.g. a <ul> wrapping a collection of <li>
  • CompositeView Represents a collection of ItemViews in the same way as a CollectionView, but can have a complex surrounding HTML strucutre that wraps the list, e.g. a <h1> title together with a <ul>
  • Layout Specialised ItemView that represents a "layout" of nested ItemView's each one contained in a "region" ... e.g. a header, content and footer layout
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment