Skip to content

Instantly share code, notes, and snippets.

@mikemorris
Last active December 21, 2015 04:58
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 mikemorris/6252970 to your computer and use it in GitHub Desktop.
Save mikemorris/6252970 to your computer and use it in GitHub Desktop.
Devlog: Prose Backbone.js Refactor

Following up on the new features described by @dhcole in #217, @tristen and I embarked on a refactor of the underlying structure of Prose with the goal of building a more robust application that adhered to established Backbone.js conventions.

This work builds on the mission of Prose to be a viable alternative to traditional content management systems, replacing heavy backend infrastructure and databases with text files, leveraging the power of git for version control and relying on Jekyll for quick static site generation. In addition to concrete performance gains, the revised model layer unlocks the potential for more complex functionality that could be implemented in the future, such as comparing diffs of previous versions of a file. Hopefully this refactor will encourage other developers to contribute to Prose by lowering the barrier to commmunity contributions.

History

Originally, Prose only used views and a router from Backbone.js, communicating with the GitHub API through a handful of functions that wrapped methods from github.js. However, the GitHub API is essentially a CRUD backend and, with a few minor tweaks, Backbone.js offers great support for syncing models between the client and server.

Structure

The first task was sketching out the relationships between objects accessible through the GitHub API, and determining how to break up the current large views into a nested structure of subviews, each with its own discrete functionality.

Prose Sketches

We built Backbone.js models and collections to mirror the API objects, and gradually broke functionality out of models.js and reimplemented it in the appropriate models. We then broke the large views into smaller pieces, each responsible for presenting a limited amount of information and only handling interaction in its immeadiate context. Throughout this process, we emphasized a cleaner separation of concerns, such that models would only be responsible for managing data, while views would only be responsible for presentation and handling UI interaction. This enabled us to use functionality like Backbone's model.save and model.isNew rather than parsing content or inferring state from the DOM.

Patterns

We used a dependency injection pattern to provide references to model dependencies and related UI components to subviews. This helped ensure that views would not render prematurely or re-render themselves unnecessarily (both of which happened when rendering on change or sync events).

To avoid memory leaks caused by failing to unbind event handlers, we used Backbone's listenTo method and an object on each view to keep track of all child views. Then, we extended Backbone's view.remove method to iterate over all child views and invoke their respective remove methods.

Templates

We refactored the templates in Prose to not depend on global state, and then defined single variable names for each template to avoid the with statement, significantly improving rendering speed. We also used DocumentFragment to improve performance in views responsible for rendering many subviews.

Internationalization

During this refactor, there was an emphasis on making Prose accessible to users around the world. @tristen internationalized the UI using the Transifex platform, which has already attracted translations in German, French, Brazilian Portugese, Romanian, Russian, Vietnamese and Chinese. There are future plans to enable a non-English default language for multilingual sites.

Improvements

  • Rendering several subviews individually rather than waiting for a single large view to render reduces perceived page load time.
  • Switching from a custom XHR implementation to $.ajax seamlessly added support for conditional requests and delegated _config.yml caching and invalidation to jQuery rather than handling this manually through localStorage
  • Repo view navigation now filters and re-renders the Files subview, rather than requiring a full page reload, significantly speeding up navigation.

Prose Repo Navigation

Next

Check out the issue queue if you're interested in contributing!

@mapbox/team-mapbox

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment