Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pitfalls and opportuniities of single-page appl...

Pitfalls and opportuniities of single-page applications

Slides for my "Pitfalls" talk (jQuery UK, MMT29). See also https://github.com/jzaefferer/pitfalls-examples

jzaefferer

March 28, 2012
Tweet

More Decks by jzaefferer

Other Decks in Technology

Transcript

  1. Yours truly Jörn Zaefferer <- that’s me Writing a lot

    of JavaScript since 2006 Wednesday, March 28, 2012
  2. Yours truly Jörn Zaefferer <- that’s me Writing a lot

    of JavaScript since 2006 jQuery Core, jQuery UI, QUnit, jQuery Validation Plugin Wednesday, March 28, 2012
  3. Yours truly Jörn Zaefferer <- that’s me Writing a lot

    of JavaScript since 2006 jQuery Core, jQuery UI, QUnit, jQuery Validation Plugin Even more since December 2010 Wednesday, March 28, 2012
  4. Yours truly Jörn Zaefferer <- that’s me Writing a lot

    of JavaScript since 2006 jQuery Core, jQuery UI, QUnit, jQuery Validation Plugin Even more since December 2010 Main SPA experience: SoundCloud Mobile in 2011 Wednesday, March 28, 2012
  5. “A single-page application (SPA) is a web application or web

    site that fits on a single web page with the goal of providing a more fluid user experience akin to a desktop application.” --Wikipedia, Single-page application Wednesday, March 28, 2012
  6. Single Page Applications Static files and JSON API No page

    reloads Backbone et al Wednesday, March 28, 2012
  7. $("a:not([href^=http])").click(function(event) { if (event.metaKey || event.shiftKey || event.ctrlKey) { return;

    } event.preventDefault(); SimpleHistory.pushState(this.href); }); Wednesday, March 28, 2012
  8. SimpleHistory.start(function(url, state) { var parts = URL.parse(url); var path =

    parts.path; var index = path === "/"; $(document.body).toggleClass("indexActive", index); if (!index) { var photo = photos.lookup(path); $("#photo img").attr("src", photo.src); $("#photo p").text( photo.description ); } }); Wednesday, March 28, 2012
  9. twitter.com/bassistance vs twitter.com/#!/bassistance Never available on server Only as fallback

    Not necessary, as we’ll see soon What about hashchanges? Wednesday, March 28, 2012
  10. $(document).scroll(function() { var parts = URL.parse(location.href); if (parts.path !== "/")

    { return; } var scrollTop = $(document).scrollTop(); SimpleHistory.replaceState(location.pathname, { scroll: scrollTop }); }.debounce()); Wednesday, March 28, 2012
  11. SimpleHistory.start(function(url, state) { [...] if (state.scroll) { var scrollTop =

    state.scroll; setTimeout(function() { window.scrollTo(0, scrollTop); }, 50); } [...] }); Wednesday, March 28, 2012
  12. var connect = require('connect'); var fs = require('fs'); var handlebars

    = require('handlebars'); var url = require('url'); var photos = require('./app/gallery/photos'); Wednesday, March 28, 2012
  13. function route(app) { app.get(/.../, function(request, response, next) { [...] });

    app.post(/.../, function(request, response, next) { [...] }); } Wednesday, March 28, 2012
  14. app.get(/^\/photos\/.+/, function(request, response) { var photo = photos.lookup(request.url); response.end(template({ src:

    photo.src, description: photo.description, photos: photos.data })); }); Wednesday, March 28, 2012
  15. app.get(/^\/photos\/.+/, function(request, response) { var photo = photos.lookup(request.url); response.end(template({ src:

    photo.src, description: photo.description, photos: photos.data })); }); Wednesday, March 28, 2012
  16. app.get(/^\/photos\/.+/, function(request, response) { var photo = photos.lookup(request.url); response.end(template({ src:

    photo.src, description: photo.description, photos: photos.data })); }); Wednesday, March 28, 2012
  17. // double client/server export var photos; if (typeof exports !==

    'undefined') { photos = exports; } else { photos = {}; } photos.data = [{ src: "/alligators/DSC_1165.jpg", description: "Not a crocodile" }, ...]; photos.lookup = function(url) { return photos.data.filter(function(photo) { return photo.url == url; })[0]; }; Wednesday, March 28, 2012
  18. app.get(/^\/pair\/result$/, function(request, response) { var term = url.parse(request.url, true).query.term; pair(term,

    function(result) { response.end(JSON.stringify(result)); }); }); Wednesday, March 28, 2012
  19. module.exports = function(tag, callback) { var replies = 0; var

    content = {}; function done(type, result) { content[type] = result; replies += 1; if (replies === 2) { callback(content); } } request.get(flickrUrl(tag), function(err, res, body) { done('flickr', parseFlickr(body)); }); request.get(soundcloudUrl(tag), function(err, res, body) { done('soundcloud', parseSoundcloud(body)); }); }; Wednesday, March 28, 2012
  20. $(document).ajaxError(function(event, xhr, options, error) { logError("ajax", error + ":" +

    xhr.responseText, options.url); }); Wednesday, March 28, 2012
  21. app.post("/errorlogger", function(request, response) { var form = new formidable.IncomingForm(); form.parse(request,

    function(err, fields, files) { console.log("[CLIENT " + fields.type + " error]", fields.message, fields.detail); response.end(""); }); }); Wednesday, March 28, 2012
  22. Worth the trouble? Better user experience Good first impression Good

    response times Stable product Wednesday, March 28, 2012
  23. Further reading: https://github.com/jzaefferer/pitfalls-examples Short link: http://git.io/Hirx3Q Further meeting: @cgnjs -

    colognejs.de - 12.4.2012, MVC frameworks Feedback please: http://www.surveymonkey.com/s/2F63MML Short link: http://svy.mk/xtVS2F @bassistance - [email protected] Wednesday, March 28, 2012