Building Isomorphic Apps
Spike Brehm
@spikebrehm
@spikebrehm
@AirbnbNerds
Spike Brehm
Isomorphic
JavaScript.
WTF is Isomorphic
JavaScript?
JavaScript code that can be
shared between environments.
JavaScript code that can be
shared between environments.
JavaScript code that can be
shared between environments.
JavaScript code that can be
shared between environments.
Backend
Ruby
Python
Java
PHP
Node.js
Persistence
Client
JavaScript
Shared
JavaScript
DOM manipulation UX
View layer
Applic...
Etymology of
“Isomorphic
JavaScript”.
adjective
corresponding or similar in form and relations.
i·so·mor·phic
i·so·mor·phic
formsame
http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/
“monomorphic”
“heteromorphic”
“homomorphic”
“polymorphic”
You’re using it wrong!
Isomorphic
JavaScript
in the wild.
Flickr
Flickr
! Yahoo’s Modown libraries
(successor to Mojito).
Flickr
Instagram*
Instagram*
! Facebook’s React library
in a Django app.
Instagram*
Airbnb Mobile
Airbnb Mobile
! Airbnb’s Rendr library, built on
Backbone and Express.
Airbnb Mobile
Asana
! Entire App runtime synced
between client & server.
Asana
Meteor
! Realtime app framework.
Meteor
Wy go to the
trouble?
Initial pageload speed.
Performance
Crawlable single-page apps.
SEO*
Reduce code duplication.
Maintainability
Run code any...
Isomorphic use
cases.
• Templating
• I18n
• Date & currency formatting
• Application logic
• Routing
• Model validation
• API interaction
• ...?...
Isomorphic
JavaScript is a
spectrum.
Entire view
layer and app
logic shared
Small bits of
view layer or
logic shared
Many
abstractions
Few
abstractions
View layer
shared
Entire app
runtime synced
between client
& server
Isomorphic
JavaScript can be
or
shimmed per
environment .
environment-
agnostic
Does not depend on browser-specific
properties (window) or server-specific
properties (process.env,
req.cookies).
Environmen...
Example: Handlebars.js
var template = !
'<ul>' !
'{{#each posts}}' !
' <li>{{title}}</li>' !
'{{/each}}' !
'</ul>'!
;!
 !
...
Provide shims for accessing
environment-specific properties so
module can expose a single API.
window.location.pathname	
vs...
Example: Superagent
superagent!
.get('/api/posts.json')!
.end(function(res) {!
if (res.status === 200) {!
console.log("Pos...
Abstractions.
Abstraction: User Agent
Client navigator.userAgent
Server req.get('user-agent')
Abstraction: Cookies
Client
document.cookie =!
'myCookie=1; Domain=.example.org';
Server
res.setHeader(!
'Set-Cookie: myCo...
Abstraction: Redirects
Client
document.location.href = '/login';!
!
window.pushState({}, '', '/login');
Server res.redirec...
How to isomorph.
Let’s write a module that abstracts the
setting of cookies, providing the same
API for client & server.
setCookie('myCookie', 'the value');
setCookie('myCookie', 'the value');
document.cookie = 'myCookie=the%20value';
or
res.setHeader('Set-Cookie: myCookie=the%2...
setCookie('myCookie', 'the value', {!
path: '/',!
domain: '.example.org',!
expires: new Date(2014, 12, 31)!
});
document.c...
Eww, that looks hard.
NPM & Browserify
to the rescue.
Browserify
Use CommonJS to require()
modules in the browser.
Browserify
Package dependencies from
node_modules into our bundle.
How do we make a
shimmed-per-
environment module?
Utilize package.json “browser” field.
{!
"name": "set-cookie",!
"dependencies": {...}!
}!
!
!
!
{!
"name": "set-cookie",!
"dependencies": {...},!
"browser": "./lib/client.js"!
}!
!
!
Swap out the entire
implementation.
{!
"name": "set-cookie",!
"dependencies": {...},!
"browser": {!
"./lib/node.js": "./lib/client.js"!
}!
}!
Swap out specific...
{!
"name": "set-cookie",!
"dependencies": {...},!
"browser": {!
"./lib/node.js": "./lib/client.js",!
"cookie": "cookie-bro...
Let’s build `set-cookie`.
https://github.com/spikebrehm/set-cookie
Module structure
.!
"## index.js!
"## lib!
$   %## setter!
$   "## index.js!
$   %## client.js!
"## node_modules!
$   %## ...
// ./index.js!
!
var cookie = require('cookie');!
var setter = require('./lib/setter');!
!
module.exports = function(name,...
// ./lib/setter/index.js!
!
module.exports = function setter(cookieStr, options) {!
  var res = options && options.res;!
!...
// ./lib/setter/client.js!
!
module.exports = function setter(cookieStr) {!
  document.cookie = cookieStr;!
};
// ./package.json!
!
{!
"name": "set-cookie",!
"dependencies": {!
"cookie": "^0.1.2"!
},!
"browser": {!
"./lib/setter/inde...
// ./index.js!
!
var cookie = require('cookie');!
var setter = require('./lib/setter');!
!
module.exports = function(name,...
How to isomorph
in a nutshell.
@spikebrehm

@AirbnbNerds
Thanks!
More resources available at

http://spike.technology
@spikebrehm

@AirbnbNerds
Thanks!
More resources available at

http://spike.technology
We’re hiring!!!We’re hiring!!!We’re...
JSConf US 2014: Building Isomorphic Apps
JSConf US 2014: Building Isomorphic Apps
Upcoming SlideShare
Loading in …5
×

JSConf US 2014: Building Isomorphic Apps

3,942 views

Published on

Slides from Spike Brehm's talk at JSConf US 2014. Topics include the etymology of "Isomorphic JavaScript", examples is isomorphic apps in the wild, reasons behind the growing trend towards isomorphic apps, and how to build an isomorphic module using Browserify & NPM.

Published in: Technology
0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,942
On SlideShare
0
From Embeds
0
Number of Embeds
1,313
Actions
Shares
0
Downloads
39
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide

JSConf US 2014: Building Isomorphic Apps

  1. 1. Building Isomorphic Apps Spike Brehm @spikebrehm
  2. 2. @spikebrehm @AirbnbNerds Spike Brehm
  3. 3. Isomorphic JavaScript.
  4. 4. WTF is Isomorphic JavaScript?
  5. 5. JavaScript code that can be shared between environments.
  6. 6. JavaScript code that can be shared between environments.
  7. 7. JavaScript code that can be shared between environments.
  8. 8. JavaScript code that can be shared between environments.
  9. 9. Backend Ruby Python Java PHP Node.js Persistence Client JavaScript Shared JavaScript DOM manipulation UX View layer Application logic Routing
  10. 10. Etymology of “Isomorphic JavaScript”.
  11. 11. adjective corresponding or similar in form and relations. i·so·mor·phic
  12. 12. i·so·mor·phic formsame
  13. 13. http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/
  14. 14. “monomorphic” “heteromorphic” “homomorphic” “polymorphic” You’re using it wrong!
  15. 15. Isomorphic JavaScript in the wild.
  16. 16. Flickr
  17. 17. Flickr
  18. 18. ! Yahoo’s Modown libraries (successor to Mojito). Flickr
  19. 19. Instagram*
  20. 20. Instagram*
  21. 21. ! Facebook’s React library in a Django app. Instagram*
  22. 22. Airbnb Mobile
  23. 23. Airbnb Mobile
  24. 24. ! Airbnb’s Rendr library, built on Backbone and Express. Airbnb Mobile
  25. 25. Asana
  26. 26. ! Entire App runtime synced between client & server. Asana
  27. 27. Meteor
  28. 28. ! Realtime app framework. Meteor
  29. 29. Wy go to the trouble?
  30. 30. Initial pageload speed. Performance Crawlable single-page apps. SEO* Reduce code duplication. Maintainability Run code anywhere. Flexibility
  31. 31. Isomorphic use cases.
  32. 32. • Templating • I18n • Date & currency formatting • Application logic • Routing • Model validation • API interaction • ...? Isomorphic use cases.
  33. 33. Isomorphic JavaScript is a spectrum.
  34. 34. Entire view layer and app logic shared Small bits of view layer or logic shared
  35. 35. Many abstractions Few abstractions
  36. 36. View layer shared Entire app runtime synced between client & server
  37. 37. Isomorphic JavaScript can be or shimmed per environment . environment- agnostic
  38. 38. Does not depend on browser-specific properties (window) or server-specific properties (process.env, req.cookies). Environment-agnostic
  39. 39. Example: Handlebars.js var template = ! '<ul>' ! '{{#each posts}}' ! ' <li>{{title}}</li>' ! '{{/each}}' ! '</ul>'! ;!  ! var templateFn = Handlebars.compile(template)! , html = templateFn({posts: posts});
  40. 40. Provide shims for accessing environment-specific properties so module can expose a single API. window.location.pathname vs. req.path Shimmed per environment
  41. 41. Example: Superagent superagent! .get('/api/posts.json')! .end(function(res) {! if (res.status === 200) {! console.log("Posts:", res.body);! } else {! console.error("Error");! }! });
  42. 42. Abstractions.
  43. 43. Abstraction: User Agent Client navigator.userAgent Server req.get('user-agent')
  44. 44. Abstraction: Cookies Client document.cookie =! 'myCookie=1; Domain=.example.org'; Server res.setHeader(! 'Set-Cookie: myCookie=1; ' +! 'Domain=.example.org'! );
  45. 45. Abstraction: Redirects Client document.location.href = '/login';! ! window.pushState({}, '', '/login'); Server res.redirect('/login');
  46. 46. How to isomorph.
  47. 47. Let’s write a module that abstracts the setting of cookies, providing the same API for client & server.
  48. 48. setCookie('myCookie', 'the value');
  49. 49. setCookie('myCookie', 'the value'); document.cookie = 'myCookie=the%20value'; or res.setHeader('Set-Cookie: myCookie=the%20value;');
  50. 50. setCookie('myCookie', 'the value', {! path: '/',! domain: '.example.org',! expires: new Date(2014, 12, 31)! }); document.cookie =! 'myCookie=the%20value; Domain=.example.org; ' +! 'Path=/; Expires=Sat, 31 Jan 2015 05:00:00 GMT';
  51. 51. Eww, that looks hard.
  52. 52. NPM & Browserify to the rescue.
  53. 53. Browserify Use CommonJS to require() modules in the browser.
  54. 54. Browserify Package dependencies from node_modules into our bundle.
  55. 55. How do we make a shimmed-per- environment module? Utilize package.json “browser” field.
  56. 56. {! "name": "set-cookie",! "dependencies": {...}! }! ! ! !
  57. 57. {! "name": "set-cookie",! "dependencies": {...},! "browser": "./lib/client.js"! }! ! ! Swap out the entire implementation.
  58. 58. {! "name": "set-cookie",! "dependencies": {...},! "browser": {! "./lib/node.js": "./lib/client.js"! }! }! Swap out specific files.
  59. 59. {! "name": "set-cookie",! "dependencies": {...},! "browser": {! "./lib/node.js": "./lib/client.js",! "cookie": "cookie-browser"! }! } Swap out dependencies.
  60. 60. Let’s build `set-cookie`. https://github.com/spikebrehm/set-cookie
  61. 61. Module structure .! "## index.js! "## lib! $   %## setter! $   "## index.js! $   %## client.js! "## node_modules! $   %## cookie
  62. 62. // ./index.js! ! var cookie = require('cookie');! var setter = require('./lib/setter');! ! module.exports = function(name, value, options) {!   var cookieStr = cookie.serialize(name, value, options);!   setter(cookieStr, options);! };
  63. 63. // ./lib/setter/index.js! ! module.exports = function setter(cookieStr, options) {!   var res = options && options.res;! !   if (!res)! throw new Error('Must specify `res` ' +! 'when setting cookie.’);! !   res.setHeader('Set-Cookie', cookieStr);! };
  64. 64. // ./lib/setter/client.js! ! module.exports = function setter(cookieStr) {!   document.cookie = cookieStr;! };
  65. 65. // ./package.json! ! {! "name": "set-cookie",! "dependencies": {! "cookie": "^0.1.2"! },! "browser": {! "./lib/setter/index.js": "./lib/setter/client.js"! }! }
  66. 66. // ./index.js! ! var cookie = require('cookie');! var setter = require('./lib/setter');! ! module.exports = function(name, value, options) {!   var cookieStr = cookie.serialize(name, value, options);!   setter(cookieStr, options);! };
  67. 67. How to isomorph in a nutshell.
  68. 68. @spikebrehm @AirbnbNerds Thanks! More resources available at http://spike.technology
  69. 69. @spikebrehm @AirbnbNerds Thanks! More resources available at http://spike.technology We’re hiring!!!We’re hiring!!!We’re hiring!!!We’re hiring!!!We’re hiring!!!We’re hiring!!!

×