This document discusses using a proxy server to render single page applications for search engines and legacy browsers. It introduces the concept of a server-side backbone that runs the same backbone application code on both the client and server. This allows rendering the initial HTML on the server to avoid problems with robots and speeds up loading for users. It also discusses some of the challenges in implementing this approach like emulating the DOM and browser APIs on the server. Overall it presents server-side rendering as a way to solve crawlability and legacy browser support problems for single page apps.
4. UsE a PrOxY fOr LeGaCy BrOwSeRs
Browser
Browser
interfaces
Server
API
Full
app
Plain
HTML
App
Proxy
5. WhAt Do I GaIn?
• Solve the Robot problem – remove double code paths
• Speed up time to first render – bootstrap your DOM
• Potentially solve the “legacy browser” problem
• Ease your test automation – mocking your API/App
6. WhAt DoEs iT TaKe tO AcHiEvE?
• JavaScript support (node.js)
• Shared module loader (Require.js / Browserify)
• Some way to emulate/abstract out DOM
• Some shims for Browser APIs (XHR, localStorage etc…)
• Some way to tell your app has completed rendering
8. GrAiLs: WhAt yOuR ApP MiGhT LoOk LiKe
• Some partial layering model
Application Logic & Templates
• App touches the browser APIs
Backbone
through all the layers
jQuery
Browser API
• Everything needs server-side
JavaScript Runtime
shims!
Runs on both as-is
Compatibility
Layer
Platform Specific
9. GrAiLs: PrOxY BrOwSeR (PhAnToM.Js)
Browser • Full WebKit implementation on
server-side
• Runs on its own process/server
Reverse Proxy
smart
clients
dumb
clients • Context sharing with Phantom.js
App Server Proxy Browser
process is tricky
• Chromium Embedded Framework
& Node.js would even better?
10. GrAiLs: TeMpLaTe ShArInG (tHe nOrMaL wAy)
Templates • Share the templates on client
Data Representation and server
Application Logic Server Logic • Separate codebases for
Backbone compositing the page fragments
jQuery
Browser API • Simple to understand
JavaScript
Runtime
Any Runtime • Double code paths: Double
testing, maintenance etc.
Runs on both as-is
Compatibility
Layer
Platform Specific
11. GrAiLs: ShArEd ClIeNt-sErVeR Fw (DeRbY, MeTeOr)
• Full app frameworks that hide
Application Logic & Templates
the DOM
Custom Framework
• Hide client/server messaging
(socket.io etc.)
• Meteor still uses PhantomJS to
JavaScript Runtime
render for robots?
• Lock-in to a certain
development model
Runs on both as-is
• Lock-in to a certain backend
Compatibility
Layer
Platform Specific
12. GrAiLs: SeRvEr-sIdE DoM (JsDoM)
• JSDOM - Full JavaScript DOM
Application Logic & Templates
implementation
Backbone
• How about the other APIs?
jQuery
• Browser/HTML5 APIs is huge!
Browser API Subset
• Slow to emulate
JavaScript Runtime
Runs on both as-is
Compatibility
Layer
Platform Specific
13. GrAiLs: SeRvEr-sIdE jQuErY (ChEeRiO)
• Use jQuery for compatibility
Application Logic & Templates
Backbone
• Hide the DOM below
jQuery / Cheerio
• Limited adaptation problem
JavaScript Runtime • Potentially faster
• Changes to Backbone needed
Runs on both as-is
Compatibility
Layer
Platform Specific
14. GrAiLs: AbStRaCt oUt DoM (AiRbNb / ReNdR)
• Backbone, but abstract out all
Application Logic & Templates
DOM manipulation from view
Backbone
manipulation
Adaptation Layer
• AirBNB - Concatenate
templates on server
JavaScript Runtime • No jQuery, no DOM access
• Is it the same anymore?
Runs on both as-is
Compatibility
Layer
Platform Specific
15. GrAiLs: CoMpArIsOn Template
Sharing
Templates
Your
Typical
App
Shared
Client-‐Server
FW
Data Representation
Application Logic & Templates Application Logic & Templates Application Logic Server Logic
Backbone Custom Framework Backbone
jQuery jQuery
Browser API Browser API
JavaScript Runtime JavaScript Runtime JavaScript Any Runtime
Runtime
DOM
Abstracted
out
JSDOM
Cheerio
Application Logic & Templates Application Logic & Templates Application Logic & Templates
Backbone Backbone Backbone
Adaptation Layer jQuery jQuery / Cheerio
Browser API Subset
Runs on both as-is
Compatibility
JavaScript Runtime JavaScript Runtime JavaScript Runtime Layer
Platform Specific
16. AlMoSt aLl oF oUr aPpS aRe BaCkBoNe & JqUeRy
YoU cAn’t tEaCh oLd dOg nEw tRiCkS
17. BaCkBoNe-SeRvErSiDe – oUr DeSiGn PrInCiPlEs
• We do not need to be a full browser
• We cannot expect the world to change our way
• API compatibility is our friend
• Make it a polyfill, not a library or framework
• Do not assume anything else than Backbone
• Retain API compatibility, hide the dirty tricks if possible
• Retain the possibility to use 3rd party JavaScript libs
• Keep app specific changes to minimum
18. InTrOdUcInG BaCkBoNe-SeRvErSiDe
• Run the same Backbone SPA on both
Application client and server with minimal extra
conventions
Backbone
• Removes Backbone DOM depencies
jQuery / Cheerio • Cheerio jQuery subset for DOM
Browser / Adaptation Layer
manipulation
• Polyfills for Cheerio (events, ajax)
JavaScript Runtime
Things you may need to change in your app:
• Stick to a subset of jQuery (Cheerio)
• Use a dependency manager that you can
run on both ends (AMD/RequireJS,
CommonJS/Browserify)
• Implement a messaging mechanism
between your node.js server and your app
19. SeRvEr-sIdE BaCkBoNe RePlAcEmEnTs
• The classes you typically use will run
as-is
Collection
Router
Model
• The classes that touch the DOM
View
underneath need changes
sync
We stub out/replace a few things
History
jQuery
Ajax
• jQuery: Cheerio and its fake DOM
• Ajax: Replace jQuery.ajax with a 3rd
party node.js module
Runs on both as-is
Compatibility • History: Trim away DOM specifics
Layer
Platform Specific (window.navigator.location etc.)
20. WhEn ArE We ReAdY tO SeNd tHe PaGe BaCk?
Browser / Server
One way on how to handle
parse path /
pushState
Inject to DOM the problem
Backbone App
• Use Backbone events for
Router messaging
handle
route
verify all
states
pass the
results • Single point of control
Model View (App Singleton/Router)
fetch
models
notify render notify
• All relevant objects have an
Legend: observable state
Server API
direct call
serve
JSON
event
21. FeAtUrE dEtEcTiOn – A MuSt HaVe?
• Require.js is hard to get right on the both ends
• Conditional switches between jQuery and Cheerio needed
• Some client-slide libraries just won’t load
• Typical applications use DOM and Browser APIs directly
• Typical 3rd party libraries use DOM & Browser APIs
extensively
à You will benefit from a feature detection library
23. BaCkBoNe-SeRvErSiDe – WoRk iN PrOgReSs
• It is still experimental, but already demonstrable
• Contributions wanted at our GitHub at
SC5/backbone-serverside
• An article in Mozilla Hacks just got out
• Some of the near-term work involves
• Handling feature detection (analytics, DOM events)
• Cross-request user state management (localStorage adapters?)
• Concurrency handling (currently we have single, shared DOM)
• Samples on robot & browser detection (express-device)
25. LeT’s SoLvE tHe CrAwLaBiLiTy PrObLeM!
LaUrI SvAn
Software Architect, SC5 Online Ltd
https://github.com/laurisvan
@laurisvan
HtMl5 eXpErTiSe aT yOuR sErViCe