A Lecture given in Aalto University course "Design of WWW Services".
Single page app is already several years old web application paradigm that is now gaining traction due to the interest towards HTML5 and particularly cross-platform mobile (web) applications. The presentation overviews the single page application paradigm and compares it with other web app paradigms.
The presentation uses Backbone.js as the sample and gives practical tips on how to best structure Backbone.js applications. It contains an extensive set of tips and links in the notes section.
The reader is adviced to download the presentation for better readability of the notes.
2. About Lauri & SC5 Online
• ”Powerhouse for software projects”
• HUT graduate, Information Networks
• 15 years in software engineering business
• A few startups & corporations behind
• Now in SC5 Online as a Software Architect
• Specializes in HTML5 application development
• Located in Helsinki (Kamppi) + Jyväskylä (Innova 2)
• Founded in 2006, employs 50 people
• Customers e.g. Sanoma, YLE, Veikkaus, F-Secure
• blog.sc5.io, twitter: @sc5io
3. Single-page Application
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
4.
5. Single-page Application
Single page apps typically have
– “application like” interaction
– dynamic data loading from the server-side API
– fluid transitions between page states
– more JavaScript than actual HTML
They typically do not have
– support for crawlers (not for sites relying on search traffic)
– support for legacy browsers (IE7 or older, dumbphone
browsers)
6. SPAs Are Good For …
• “App-like user experience”
• Binding to your own (or 3rd party) RESTful API
• Replacement for Flash or Java in your web pages
• Hybrid (native) HTML5 applications
• Mobile version of your web site
The SPA sweet spot is likely not on web sites,
but on content-rich cross-platform mobile apps
7. App-like User Experience
Note: These (all) are not our work but showcases that Finns can do good stuff!
8. Native Apps vs. Hybrid/Mobile Web Sites
“The real problem with apps was that when people read on electronic
media, they expect the stories to possess the linky-ness of the Web—
but stories in apps didn’t really link.”
“Software development of apps was much harder than publishers had
anticipated, because they had hired Web developers who knew
technologies like HTML, CSS, and JavaScript. Publishers were
astonished to learn that iPad apps were in fact real, if
small, applications, written mostly in a language called Objective
C, which no one in their Web-dev departments knew. Publishers
responded by outsourcing app development, which was
expensive, time-consuming, and unbudgeted.”
Why Publishers Don't Like Apps in MIT Technology Review
9. SPAs and Other Web App Architectures
Server-side Server-side + AJAX PJAX SPA
What Server round-trip on Render initial page on Render initial page on Serve static page
every app state change server, state changes server, state changes skeleton from server;
on the client on server, inject into render every change on
DOM on client-side client-side
How UI code on server; links UI code on both ends; UI code on server, UI code on client,
& form posting AJAX calls, ugly server client to inject HTTP, server API
API server API if you like
Ease of development
UX & responsiveness
Robots & old browsers
Who’s using it? Amazon, Wikipedia; Facebook?; Twitter, Basecamp, Google+, Gmail, FT;
banks, media sites etc. widgets, search GitHub mobile sites, startups
11. Anatomy of a Backbone SPA
• Application as a „singleton‟
reference holder
• Router handles the navigation and
toggles between views
• Models synchronize with Server
API
• Bulk of the code in views
• All HTML in templates
12. SPA Client-Server Communication
• HTML and all the assets are loaded in
first request
• Additional data is fetched over
XMLHTTPRequest
• In addition to normal server stack, you
need to have API endpoints in the same
level as presentation layer
• If you want to go real-time, WebSockets
(socket.io) can help you
• When it gets slow, cluster the backend
behind a caching reverse proxy like
Varnish
13. Sample App Stack
App
Backbone App When the app gets complex, you need modularity
(Backbone Router) require.js
Views Models
Router (Backbone View) (Backbone Model)
(Backbone Router) When the devices have differences, you need
feature detection (only a few shims really work)
modernizr
(feature
Backbone
LayoutManager
Handlebars modernizr, semantic.gs
(template engine)
detection) (view utility)
DOMReady
fastclick
(normalise
(bootstrapping) View & Templating Stack When you want to have an optimized app,
click handling)
Underscore.js
(object/array
Backbone variability or a native app, you need builds
grunt
(MVC framework)
utils)
Cross-Browser jQuery
Compatibility Utility Belt (DOM access)
RequireJS
(dependency mgmt)
Sample boilerplate available at SC5 GitHub
320 and Up Semantic.gs
(boilerplate) HTML5 Foundation (boilerplate)
Our component
Bower LESS Jasmine Grunt Node.js & Express
(package mgmt) (CSS) (unit tests) (builds) (web/API server) 3rd party component
Build, Testing & Deployment Subsystems
14. Handling Navigation (location)
• Browsers already have navigation controls; support them
• HTML5 pushState exists exactly for this purpose
• Handled by History in Backbone and $location in Angular
• Remember fallback to hashbang „#‟ with legacy browsers
• Remember to use URL rewrites in the server side
15. Handling Models (dynamic data)
• Backbone has a flat model of Collections containing Models
• Input validation (can block the invalid input, blocks on save())
• Multiple view bindings (through events)
• Custom data - model mappings (through parse())
• Synchronizing with servers
• fetch() -> GET
• save() -> POST or PUT
• delete() -> DELETE
16. Handling Models (dynamic data)
• Can be easily extended by overriding Backbone.sync()
• Real-time communications (web sockets)
• Offline use (localStorage)
• Avoid spaghetti code:
• If your UI state does not fit the server schema, override parse()
and save()
• Use the models as the state of your views
• Isolate client-server communication to models and collections
• If you ever plan to reuse your models, fix your schema and don‟t
hard-code your URLs
17. Handling Views (DOM)
• Usually your sequence is as simple as:
1.Update model triggers change in views
2.Refresh views (render) render template apply into DOM
3.Notify the other views (if for some reason they cannot listen to the
same model)
18. Handling Views (DOM)
• Avoid spaghetti code
• Backbone expects to keep Models and Views in sync
• A view should only alter the parts of DOM it owns
• A view should not call directly other views than its children
• Use the event binding facilities offered by framework
(e.g. Backbone.view.events: {})
• A few jQuery calls to alter a subset of DOM is more code and more
expensive than replacing the same subset by a template
Always drive your view changes through your model
Use events for messaging between the application parts
Use templates; usually it is ok to render the view again
19. Page Rendering – Templates
• Easier way of creating a bunch of HTML elements
• Inject HTML into DOM using $.html()
• The principle is the same in server-side: call template
with the parameters as data-object to get HTML
Samples: Handlebars, Dust.js, EJS, Google Closure
Templates
See: LinkedIn comparison of template engines
20. Summary
• SPA ~ MV(C) Pattern ~ Server API driven app
• A toolbelt of a JS framework and supplementary libraries
• Still fairly new paradigm, not in wide use yet
• Good complement to your existing web site
• Mobile/Hybrid app
• May replace your existing site when solving the crawling
issue
21. Further Reading
• HTML5 sovellusalustana (a book by Pyry L & Jukka K)
http://www.julkaisija.fi/yleista/html5.php
• Developing Backbone.js Applications (a CC book by Addy Osmani)
https://github.com/addyosmani/backbone-fundamentals
• HTML5 Rocks as a vault of information
http://www.html5rocks.com/en/
• A catalogue of JavaScript libraries to choose among
http://www.jsdb.io/
22. Thank you !
Lauri Svan
Software Architect, SC5 Online Ltd
https://github.com/laurisvan
https://twitter.com/laurisvan
HTML5 expertise at your service
Notas del editor
Please keep your eye on notes – some slides contain a lot of good extra insight!
“App-like user experience”Touch navigationInstant response to your clicksFluid transitions between pagesCached & pre-fetched contentBinding to your own (or 3rd party) RESTful APIEase of populating modelsReplacement for Flash or Java in your web pagese.g. FlipBoard, LinkedIn iPadHybrid (native) HTML5 applicationse.g. FlipBoard, LinkedIn iPadApache Cordova, Embedded WebViews, Tizen, Windows 8Mobile version of your web sitem.veikkaus.fi, plus.hbl.fi, app.ft.com
Note: Ease of development = (design, implementation, testing, maintenance)Testing and maintenance are the hard partsServer-sideThe good old way; write that server-side templateDevelopment: There are dozens of FWs for every major language for thisHow to deal with user state? Store on cookie; Store on session memory clustering?Selenium will test your site alrightUX: How to get that app-like experience with 500ms clicks? Transitions? Animations?Robots: No problem if you usecanonicalurls & pagesthemselvesdon’trequireuserstateServer-side + AJAXDevelopment: The problem is in transmitting the UI state & synchronize it in both ends;The simple test: Click refresh on an AJAX page – did you get what you expected?How did you plan to test your system after all? What does your API look like?Spaghetti architectureUX: Can be made fast & responsive, but it’s tedious.Robots: If you’ve got even a single bit that is rendered on client side only, I’m sorry.PJAXDevelopment: The concept is very simple but I’m not aware of any widely used, ready-made frameworks for itBold attempts: https://github.com/defunkt/jquery-pjax, https://github.com/rails/turbolinksNo idea on how to automate testing on itUX: The pages can be pretty fast, but likely the future states are not anticipated & cacheable (like in SPAs)Robots: Twitter actually did SPA before and moved back to PJAX (I believe they missed the searchability too much)SPADevelopment: Clean model (most of the FWs use MVC model, and the future content can be fetched within model without affecting the current view)Usually server-side API is RESTful & clean and hence can be tested easily; testing the client UI is a bit so-soUX: Can have all the bells and whistlesRobots & old browsers: Test for Google (likely won’t work), other crawlers won’t work; IE7/8 and feature phone browsers will cause headacheSPA is not always the only choice, there are reasons for other choices, tooWhy Twitter went back SPA to PJAX:http://engineering.twitter.com/2012/05/improving-performance-on-twittercom.html
In the end, all of the frameworks do the same thing. There is no need to switch between them on-project basis (learning always takes some time)Backbone: Simple MVC model, only ~ 800 LOC. Your grandmother would get it. No data bindings built in.Angular.js: “What DOM should have been”. Sophisticated data binding with DOM and your JavaScript model.Knockout: One of the earliest frameworks. Data binding with some enforcements on your coding styleEmber: The biggest framework (by LOC). Very object-oriented (you will drift away from DOM)
Utility toolbelts:jQuery: The de-facto DOM manipulation libraryUnderscore.js: Object and Array manipulationClient-side templating engines:Handlebars: Simple templating language that does not break HTMLDust.js: Feature-rich templating language (partials, streaming etc.)ModularizationRequire.js: Module framework for JavaScriptLESS and SASS: Stylesheet languages done rightBrowser compatibilityModernizr: HTML5 and CSS3 feature detectionUI Widget FrameworksBootstrap: Customizable UI widgetsjQuery Mobile: ThemableiOS like widgets for mobile UisBuilding & Test AutomationGrunt: JavaScript/Node.js based build systemJasmine: Behavior-driven test framework; works for TDD-style processQUnit: JavaScript unit testing framework developed by jQuery communityServer APIs made easy:Node.js: JavaScript server-side stack; great for quick no nonsense API servers;express.js: Web application framework for Node.jsApplication BoilerplatesYeoman: An ambitious, grunt-based boilerplate creation utility servers;Backbone boilerplate: Simple creation of Backbone based appsHTML Boilerplates & CSS Grids320andup: Responsive boilerplate with special emphasis on mobileHTML5 Boilerplate: The classic HTML5 app structureSemantic.gs: Easy an customizable CSS grid systemPackaging into a native app:Apache Cordova: ex. PhoneGap; packaging as a hybrid app for multi-platform
Browser controls:Back/ForwardReloadBookmarkingSome samples on handling URL rewriteshttp://www.josscrowcroft.com/2012/code/htaccess-for-html5-history-pushstate-url-routing/
In most of the cases the flat model is ok, because you don’t want to display multiple levels of hierarchy in a single page/viewYou can extend Backbone to support deeper structures, you will need it if you want to avoid making multiple server queriesIf your structure is static, your Collection can nest other Collections as children (AFAIK Collections can’t have Collections in place of Models)You need to write a custom parse() that will notify your child collections abIt’s complicated…Backbone has a fundamental flaw in blocking input validation:In most of the cases, the user input (e.g. for text) is invalid; Backbone blocks that. The workaround is to
For better real-time communications support, see socket.io
When using Angular, you don’t need to do a single thing to map your model changes back to DOM
Note: In most of the cases you would just want to re-render the view (unless it owns the whole DOM) for changing the state in the UI.Exception cases:You have an input form and you don’t want to lose focusYour DOM subset is huge (e.g. a whole list of a few hundred items)Some highly interactive things like sliders
Each template engine works the same wayCompile the template into JavaScript function JavaScript functionCall with parameters HTML stringApply the string into DOM -> DOM elementsAngular is different in this regard, as the “templates” are readily as part of DOM and the manipulation happens on DOM level, not HTML levelIn basic use, comparing engines is almost pointless - pick one and stick to itSome things you might want to look for if you have a fancy application & complex templatesLocalisationTemplate inheritance (when you have a lot of redundant pages)Streaming (especially if you use the same template engine on server-side)