Alexey Vasiliev

  • 8+ years experience
    • Linux and Databases administrator
    • Web and Mobile developer (Ruby, Java, JavaScript, Objective-C, C/C++)
  • Open-Source developer
    • Webp-ffi for Ruby
    • MongodbLogger for Rails
    • SMTRails and SHTRails (shared templates for rails)
    • SkypeKit for Ruby
me

Before Backbone.js

JS templates

  • Mustache.js
  • Handlebars.js
  • Hogan.js
  • JsRender
  • Underscore.js
  • doT.js
  • MaskJS
  • others...
mustache

JS templates comparison

JS templates

Scalable JavaScript Application Architecture

toolbox

A JavaScript library is like a toolbox

International Space Station

http://www.csulb.edu/colleges/coe/ae/engr370i/ch09/chap5_2n3/image9.jpg

Web Application Module

Scalable JavaScript Application Architecture

an independent unit of functionality that is part of the total structure of a web application

Web Application Module

Scalable JavaScript Application Architecture

  • Each module has its own sandbox
  • Each part of the architecture is like a puzzle piece
  • The web application is created as a result of all parts doing their job
  • Modules must stay within their own sandboxes
  • Modules only know the sandbox
  • The sandbox also acts like a security guard
  • When modules are loosely coupled, removing a module doesn't break the others
  • The application core handles errors
  • Each part can be tested separately

Backbone.js

backbonejs.org

backbonejs

Dependency

Backbone.js

  • Underscore.js
  • json2.js
  • jQuery or Zepto
  • Template engine (if not will be use Underscore.js template)

Backbone.Events

Backbone.js

Events is a module that can be mixed in to any object, giving the object the ability to bind and trigger custom named events

Methods:

  • on
  • off
  • trigger

Backbone.View

Backbone.js

  • initialize
  • el
  • render
  • remove

this.el properties:

  • tagName
  • className
  • id
  • attributes

Backbone.Model

Backbone.js

  • initialize
  • get/set/has/unset
  • defaults
  • toJSON
  • fetch
  • save/destroy
  • validate
  • url/urlRoot
  • isNew
  • hasChanged

Backbone.Collection

Backbone.js

  • initialize
  • model
  • models
  • toJSON
  • Underscore Methods
  • add/get/remove/reset/fetch
  • at
  • length
  • comparator
  • url

Backbone.Router && Backbone.History

Backbone.js

  • initialize
  • routes
  • route
  • navigate
  • Backbone.history.start()

Naming convention

Backbone patterns



   window.App = {
       ...
   };

   App.Photo = Backbone.Model.extend({
       ...
   };


       

   Models:                    App.Photo
   Collections:               App.Photos
   Views:                     App.PhotoView
   Main router:               App.Router
   Custom routers:            App.SpecialRouter

   Router instance:           App.router
   View instances:            App.photoView
   Singleton model instances: App.photo
   Collection instances:      App.photos
       

Naming convention: two-level namespace

Backbone patterns


 Models:                    App.Models.Photo
 Collections:               App.Collections.Photos
 Views:                     App.Views.Photo
 Routes:                    App.Routes.Photo

     

Bootstrapping data

Backbone patterns

  <body>
      ...

      <script>
        App.photos = new Photos([
          { id: 2, name: "My dog", filename: "IMG_0392.jpg" },
          { id: 3, name: "Our house", filename: "IMG_0393.jpg" },
          { id: 4, name: "My favorite food", filename: "IMG_0394.jpg" },
          { id: 5, name: "His bag", filename: "IMG_0394.jpg" },
          ...
        ]);
      </script>
    </body>
      

Inline templates

Backbone patterns

  <script type="text/html" id="template-contact">
    <div class='contact'>
      <strong><%= name %></strong>
      <span><%= email %></span>
    </div>
  </script>
      

JST templates

Backbone patterns

  window.JST = {};

  window.JST['person/contact'] = _.template(
      "<div class='contact'><%= name %> ..."
  );

  window.JST['person/edit'] = _.template(
      "<form method='post'><input type..."
  );
      

Mixins

Backbone patterns

  mergeMixin: (view, mixin) ->
    _.defaults view::, mixin
    _.defaults view::events, mixin.events
    if mixin.initialize isnt `undefined`
      oldInitialize = view::initialize
      view::initialize = ->
        mixin.initialize.apply this
        oldInitialize.apply this

 mergeMixin(Test.Views.PollsShow, Test.Mixin.PollsTabs)
      

Mixins

Backbone patterns

  Test.Mixin.PollsTabs =
  events:
   'click .poll_tab_link'              : 'pollTabOpen'
   'click .voters_tab_link'            : 'votersTabOpen'

  pollTabOpen: (e) ->
   e.preventDefault()
   Backbone.history.navigate("admin/polls/#{@model.get('id')}", true)

  votersTabOpen: (e) ->
   e.preventDefault()
   Backbone.history.navigate("admin/polls/#{@model.get('id')}/voters", true)
     

Common problems

Things outside views

Common problems

Put things in your view class code as much as possible.

Event handlers outside views

Common problems

Every time you make an event handler outside a view class, consider making a new view class.


      App.PhotoView = Backbone.View.extend({
        ...
      });

      // AVOID this!
      $("a.photo").click(function() { ... });
    

Zombie Views

Common problems


  Backbone.View::destroyView = ->
    @remove()
    @unbind()
    @onDestroyView()  if @onDestroyView
    
  class PiroPopup.Views.PopupIndex extends Backbone.View
    initialize: (options) ->
      @collection.on 'add', @render
      @collection.on 'reset', @render
      PiroPopup.globalEvents.on "update:pivotal:data", @updatePivotalState
    onDestroyView: =>
      @collection.off 'add', @render
      @collection.off 'reset', @render
      PiroPopup.globalEvents.off "update:pivotal:data", @updatePivotalState
    

Marionette.js

What is Marionette.js?

Marionette.js

Backbone.Marionette is a composite application library for Backbone.js that aims to simplify the construction of large scale JavaScript applications.

It is a collection of common design and implementation patterns found in the applications that we have been building with Backbone, and includes pieces inspired by composite application architectures, event-driven architectures, messaging architectures, and more.

Requirements:

  • jQuery v1.8+
  • Underscore v1.4.4+
  • Backbone v1.1.x
  • Backbone.Wreqr
  • Backbone.BabySitter

Components

Marionette.js

  • Marionette.Application
  • Marionette.AppRouter
  • Marionette.Callbacks
  • Marionette.CollectionView
  • Marionette.CompositeView
  • Marionette.Controller
  • Marionette.ItemView
  • Marionette.Layout
  • Marionette.Region
  • Marionette.RegionManager
  • Marionette.Renderer
  • Marionette.RequestResponse
  • Marionette.TemplateCache
  • Marionette.View

Marionette.Application

  (exports ? this).FalconApp =
    Regions:     {}
    Routers:     {}
    Mixins:      {}
    Views:       {}
    Models:      {}
    Collections: {}
    Layouts:     {}
    Utils:       {}
  class FalconApp.Application extends Backbone.Marionette.Application
    onStart: (options) =>
  # start app
  FalconApp.application = new FalconApp.Application

  $ -> FalconApp.application.start()
    

Marionette.Renderer

  # templates
  Backbone.Marionette.Renderer.render = (template, data) ->
    throw "Template '#{template}' not found!" unless HandlebarsTemplates[template]
    HandlebarsTemplates[template](data)
  # custom
  myTemplate = _.template("<div>foo</div>")
  Backbone.Marionette.ItemView.extend template: myTemplate
    

Marionette.ItemView


  class FalconApp.Views.InboxesItem extends Backbone.Marionette.ItemView
    template: 'inboxes/item'
    tagName: "tr"
    className: "state-switcher"
    modelEvents:
      'change:name': '_setName'
    events:
      'click .inbox_link': 'openInbox'
    serializeData: =>
      _.extend @model.toJSON(),
        'last_message_sent_at': @model.lastMessageSentAt()
    openInbox: (e) =>
      e.preventDefault()
      Backbone.history.navigate("inboxes/#{@model.get('id')}/messages", { trigger: true })
    _setName: =>
      @$('span.inbox_name').text(@model.get('name'))
      @$('input.edit_inbox_form_name').val(@model.get('name'))
    

Marionette.CollectionView


  class FalconApp.Views.CompaniesList extends Backbone.Marionette.CollectionView
    itemView: FalconApp.Views.CompaniesItem
    emptyView: FalconApp.Views.CompaniesEmptyItem

    initialize: ->
      # empty

    onDomRefresh: =>
      # empty
    

Marionette.CompositeView


  class FalconApp.Views.CompaniesItem extends Backbone.Marionette.CompositeView
    itemView: FalconApp.Views.InboxesItem
    getItemView: (item) => FalconApp.Views.InboxesItem
    itemViewContainer: "tbody.inboxes_list"
    template: 'companies/item'

    modelEvents:
      'change:name': 'changedName'
    events:
      'submit form.create_inbox_form':        'createInbox'

    initialize: ->
      @collection = @model.inboxes
    changedName: =>
      @$('.company_name').text(@model.get('name'))
    

Marionette.Region

Regions provide consistent methods to manage, show and close views in your applications and layouts. They use a jQuery selector to show your views in the correct place.


  MyApp.addRegions
    mainRegion: "#main-content"
    navigationRegion: "#navigation"
  # basic
  myView = new MyView()
  # render and display the view
  MyApp.mainRegion.show myView
  # closes the current view
  MyApp.mainRegion.close()
    

Marionette.RegionManager

Region managers provide a consistent way to manage a number of Marionette.Region objects within an application. The RegionManager is intended to be used by other objects, to facilitate the addition, storage, retrieval, and removal of regions from that object.


  rm = new Marionette.RegionManager()
  region = rm.addRegion("foo", "#bar")
  regions = rm.addRegions(
    baz: "#baz"
    quux: "ul.quux"
  )
  regions.baz.show myView
  rm.removeRegion "foo"
    

Marionette.Layout

A Layout is a hybrid of an ItemView and a collection of Region objects. They are ideal for rendering application layouts with multiple sub-regions managed by specified region managers.


  class FalconApp.Layouts.Messages extends Marionette.Layout
    template: 'layout/messages'
    className: 'page_body page-body row'

    regions:
      listRegion: '.list_region'
      detailsRegion: '.details_region'

    initialize: ->
      # empty

    onDomRefresh: ->
      # empty
    

Backbone.Router

  class FalconApp.Routers.Base extends Backbone.Router
    initialize: ->
      @on 'route', @_trackPageview
    _trackPageview: (trigger, args) =>
      return if window._gaq is `undefined`
      url = Backbone.history.getFragment()
      url = "/#{url}" unless /^\//.test(url)
      window._gaq.push ['_setSiteSpeedSampleRate', 100]
      window._gaq.push ['_trackPageview', url]

  class FalconApp.Routers.Inboxes extends FalconApp.Routers.Base
    routes:
      'inboxes': 'index'
    initialize: ->
      super()
    index: =>
      companies = new FalconApp.Collections.Companies
      @companiesList = new FalconApp.Views.CompaniesList(collection: companies)
      @layout.mainRegion.show @companiesList
      companies.fetch()
    

Bonus

Assembly and organization of the code

Bonus

  • Asynchronous Module Definitions (AMD) by require.js
  • Sprockets: Rack-based asset packaging
  • Yeoman (Node.js)

Automation

Bonus

  • Time is a key factor in staying productive.
  • Automate repetitive tasks to stay effective.
  • Automation isn’t about being lazy. It’s about being efficient.
  • The right tools make the difference between an artist and a craftsman.

The average front-end workflow today

Bonus

  • Setup

    • Scaffolding
    • Download libraries
    • Download templates
    • Download frameworks
  • Develop

    • Watch Sass / Less / Stylus
    • Watch CoffeeScript
    • Watch Jade / Haml
    • LiveReload
    • JS / CSS Linting
  • Build

    • Code linting
    • Running unit tests
    • Compile everything
    • Minify and concatenate
    • Generate images / icons
    • Optimize performance
    • HTTP Server
    • Deployment
    • PROFIT!!!

Automate this workflow for simple projects

Bonus

Iterative improvement

Bonus

First do it.

Then do it right.

Then do it better.

So "Progressive Enhancement" win! (sorry "Graceful Degradation")

Automate workflow for all types of projects

Bonus

  • Scaffold, write less with Yo
  • Build, preview and test with Grunt
  • Manage dependencies with Bower

Grunt

Bonus

Helps run repetitive tasks

Alternative to Rake/Cake/Make/Ant

  • grunt-responsive-images - Create multi-resolution images from a directory for src-set/srcN
  • grunt-contrib-imageoptim - Lower page-weight by applying optimizations to JPG/PNG/Gif
  • grunt-concurrent - Speed up build time by concurrently running tasks like Sass and Coffee
  • grunt-newer - Run tasks on only source files modified since the last run
  • grunt-uncss - Remove unused CSS across your project at build time

Bower

Bonus

A package manager for the web

 $ npm install -g bower
 $ bower search
 $ bower search angular
 $ bower install
 $ bower install angular --save-dev
 $ bower list
     

Yo

Bonus

It scaffolds out boilerplate

 $ npm install -g yo
 $ yo jquery-boilerplate
 $ yo bootstrap
 $ npm install generator-angular -g
 $ yo angular
     

HTML5 Storages

localStorage

HTML5 Storages

  • Key / value pairs - hash table
  • Persistent on page reloads
  • Avoids HTTP overhead of cookies
  • Great for storing user preferences

sessionStorage

HTML5 Storages

Same as localStorage but...

  • Lasts as long as browser is open
  • Opening page in new window or tab starts new session
  • Great for sensitive data (e.g. banking sessions)

Web SQL Database

HTML5 Storages

  • Client-side SQL database
  • Asynchronous & Synchronous* API
  • Basically wrapper around SQLite
  • Put processing (sorting, filtering, etc.) on client
  • Deprecated (!!!)

IndexedDB

HTML5 Storages

  • Best of localStorage/sessionStorage and Web SQL DB:
    • Object based data store
    • In-order retrieval by index or locate by key
  • Asynchronous & Synchronous API:
    • For the browser and for Web Workers

Application Cache

HTML5 Storages


  <html manifest="example.appcache">... </html>
     
   CACHE MANIFEST
   # Explicitly cached entries
   CACHE:
   index.html
   stylesheet.css
   images/logo.png
   scripts/main.js
   # static.html will be served if the user is offline
   FALLBACK:
   / /static.html
   # Resources that require the user to be online.
   NETWORK:
   *
      

File API

HTML5 Storages

  • File / FileList
  • FileReader
  • Drag & Drop Files

<Thank You!>

Contact information