Nathan Stitt



Nathan Stitt

0 0


devcomo-single-page-apps

DevComo Discoverable Single Page Apps Presentation

On Github nathanstitt / devcomo-single-page-apps

Nathan Stitt

nathan@argosity.com

http://github.com/nathanstitt

single page web apps

That are discoverable by the big G

And Bing, DuckDuckGo, etc....

single page apps

You visit the page, download a bunch of javascript, and all further requests (if any) are made via unobtrusive AJAX.

Can turn into big ball of mud

Who's seen this? (or worse, written it?)

jQuery.extend(Application.Model.prototype, {
    process: function() {
        var myVar1;
        // processing using myVar1;
        jQuery.ajax({
            url:myurl1,
            dataType:'json',
            success:function(data) {
                var myVar2;
                // process data using myVar1, set state of myVar2,
                // then send it back
                jQuery.ajax({
                    url:myurl2,
                    dataType:'json',
                    success:function(data) {
                        // do stuff with myVar1 and myVar2
                        if(!data.ok) {
                            jQuery.ajax({
                                url:myurl2,
                                dataType:'json',
                                success:mycallback
                            });
                        }
                        else {
                            mycallback(data);
                            }

                    }
                });
            }
        });
    }
});

Can be extremely fragile

JS={
  foo: function(){
    return this.bar();
  },
  bar: function(){
    return "I'm Awesome!";
  },
}

who spots it?

Why?

Most single page apps do not need to be indexable.

ask if anyone knows of any exceptions. Mention Amazon's hybrid model. 1 second, 7% converstion.

SPEED!

No Discovery Possible

Search engines do not execute Javascript

If you sell widgets, it'd be nice if people could find you when they search for 'awesome widgets for sale'

Google kind of does, but only to spot SEO tricks.

Approaches

Is far from a solved problem

Two sets of everything

  • HTML pages for all relevant sections of the app
  • Obvious DRY violition, double the work
  • Get best of both worlds though

Discourse took this approach

Javascript everywhere

  • In response to actions, send fully-redered html page to web spiders
  • Unsure of how well this actually works

Meteor is using this approach

HTML EVERYWHERE

Rails 4 includes Turbolinks to accomplish this.

Portions of the page are swapped dyncically for HTML which is fetched from server

Everything can use standard ERB (or whatever) templates

Use common templates

  • Share templates between server and client
  • Mustache, HAML, Liquid

This is what I settled on and extracted into the LiquidAssets Gem

Concept

  • Views are shared between Rails and Backbone.js
  • The webpage is initally renedered by Rails
  • Clients will execute JS to intercept navigation and use Backbone.js to render templates
  • Search engines will follow links in traditional style and Rails will render templates

Liquid Assets Template


{% include 'checkout/item' with cart %}

Categories

Rails rendering

          render :template=>'category/menu',
                 :locals=> {
                             'cart'       => @cart.as_json,
                             'categories' => @menus.as_json
                           }
          

To ensure compatability between JS and Ruby, only simple Hash and Array's are supported. Hashes must use string keys (not symbols).

Backbone.js view

class LB.View.Category.Menu extends Backbone.View

    render: ->
        this.$el.html( LB.Render( "category/menu",
          { categories: this.collection.toJSON(), cart: LB.Data.Cart } ) )
        this.attach()
        return this

    attach:->
        _.each( this.$('li'), (el)->
            model = this.collection.get( $(el).attr('data-id') )
            view = new LB.View.Category.MenuChoice({ model: model, el: el })
        ,this )
        this.onMenuSelection()
        return this

          

@coffeescript

That's it!

Questions?

nathan@argosity.com

github.com/nathanstitt/liquid_assets