Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Building Isomorphic Apps 
@spikebrehm
Spike Brehm 
____________________________ 
@spikebrehm 
@AirbnbNerds
1. Why Isomorphic JavaScript 
2. Isomorphic in the Wild 
3. How to Isomorph
Why Isomorphic JavaScript
What is Isomorphic 
JavaScript?
JavaScript code that can be shared between environments.
i·so·mor·phic 
same form
http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/
Persistence 
Client 
DOM manipulation UX JavaScript 
View layer 
Application 
logic Routing 
Backend 
Ruby 
Python 
Java 
...
Backend 
Ruby 
Python 
Java 
PHP 
Fat-Client, circa 2011 
Persistence 
Client 
DOM manipulation UX JavaScript 
View layer ...
DOM manipulation UX 
Persistence 
Client 
JavaScript 
Shared 
JavaScript 
View layer 
Application 
logic Routing 
Backend ...
Shared View Layer
DOM manipulation UX 
Persistence 
Client 
JavaScript 
Shared 
JavaScript 
View layer 
Application 
logic Routing 
Backend ...
View layer
Markup 
Data presentation 
I18n 
Date, Currency formatting 
URL formatting
Isomorphic Use Cases 
1. “Single Page Apps” that can be fully rendered on 
the server. 
2. Ambitious apps that share logic...
Why go to the trouble?
Performance 
Initial pageload speed. 
SEO* 
Crawlable single-page apps. 
Flexibility 
Run code anywhere. 
Maintainability ...
Performance
Client-rendered app 
Download 
skeleton 
HTML 
User sees 
content 
Download 
JavaScript 
Fetch data 
from API 
Evaluate 
J...
Server-rendered app 
Download 
full 
HTML 
Download 
JavaScript 
User sees 
content 
Evaluate 
JavaScript
Isomorphic JavaScript in the 
Wild
Flickr 
! Yahoo’s Modown libraries 
(successor to Mojito).
Instagram* 
! Facebook’s React library 
in a Django app.
Airbnb Mobile Web 
! Airbnb’s Rendr library, built on 
Backbone and Express.
Asana 
! Entire App runtime synced 
between client & server.
Meteor 
! Realtime app framework.
Isomorphic JavaScript is a 
spectrum
Entire view 
layer and app 
logic shared 
Small bits of 
view layer or 
logic shared
Many 
abstractions 
Few 
abstractions
How to Isomorph
Isomorphic JavaScript can be 
environment agnostic 
or 
shimmed per environment.
Environment 
agnostic 
Does not depend on browser-specific properties 
(window) or server-specific properties 
(process.en...
E X A M P L E 
Handlebars.js 
var template = ! 
'<ul>' ! 
'{{#each posts}}' ! 
' <li>{{title}}</li>' ! 
'{{/each}}' ! 
'</...
Shimmed per 
environment 
Provide shims for accessing environment-specific 
properties so module can expose a single API. ...
E X A M P L E 
Superagent 
superagent! 
.get('/api/posts.json')! 
.end(function(res) {! 
console.log(res.status, res.body,...
Abstractions
A B S T R ACT I O N 
Cookies 
Client document.cookie =! 
'myCookie=1; Domain=.example.org'; 
Server 
res.setHeader(! 
'Set...
A B S T R ACT I O N 
Redirects 
Client 
document.location.href = '/login';! 
! 
window.pushState({}, '', '/login'); 
Serve...
H AC K T I M E 
Let’s write a module that abstracts the setting of 
cookies, providing the same API for client & server.
H AC K T I M E 
setCookie('myCookie', 'the value'); 
document.cookie = 'myCookie=the%20value'; 
or 
res.setHeader('Set-Coo...
H AC K T I M E 
setCookie('myCookie', 'the value', {! 
path: '/',! 
domain: '.example.org',! 
expires: new Date(2014, 12, ...
That looks kinda hard…
NPM & Browserify* to the 
rescue
Browserify* Use CommonJS to require() modules in the 
browser.
Browserify* Package dependencies from node_modules into 
our bundle.
*or Webpack. 
Webpack is like Browserify, but with more bells-and- 
whistles included by default. 
Used by Instagram, Face...
H AC K T I M E 
Caveat: It’s Different on the Server 
app.use(function(req, res, next) {! 
...! 
! next();! 
}); 
! 
setCo...
How do we make a shimmed-per-environment module? 
Utilize package.json’s “browser” field.
{! 
"name": "set-cookie",! 
"dependencies": {...}! 
}! 
! 
! 
!
{! 
"name": "set-cookie",! 
"dependencies": {...},! 
"browser": "./lib/client.js"! 
}! 
! 
! 
Swap out the entire implemen...
{! 
"name": "set-cookie",! 
"dependencies": {...},! 
"browser": {! 
"./lib/node.js": "./lib/client.js"! 
}! 
}! 
Swap out ...
{! 
"name": "set-cookie",! 
"dependencies": {...},! 
"browser": {! 
"./lib/node.js": "./lib/client.js",! 
"cookie": "cooki...
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(...
// ./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/set...
// ./index.js! 
! 
var cookie = require('cookie');! 
var setter = require('./lib/setter');! 
! 
module.exports = function(...
Projects of Note
React 
Reactive UI component library from Facebook. 
Designed from the ground up to support isomorphic rendering. 
http://...
React 
Reactive UI component library from Facebook. 
Designed from the ground up to support isomorphic rendering. 
http://...
React 
Reactive UI component library from Facebook. 
Designed from the ground up to support isomorphic rendering. 
http://...
Fluxible 
Yahoo’s isomorphic Flux implementation: Dispatchr, Fetchr, Routr. 
Provides a way to “dehydrate” server state an...
Isobuild 
Meteor’s build system for isomorphic apps. 
Like Browserify & Webpack, uses static analysis to compute 
dependen...
Isobuild 
Meteor’s build system for isomorphic apps. 
Like Browserify & Webpack, uses static analysis to compute 
dependen...
isomorphic-tutorial 
Small sample isomorphic app, written from scratch using Handlebars/ 
React, Director (routing), and S...
isomorphic-tutorial 
Small sample isomorphic app, written from scratch using Handlebars/ 
React, Director (routing), and S...
Thanks! 
More resources available at 
http://spike.technology 
! 
@spikebrehm 
@AirbnbNerds
Building Isomorphic Apps (JSConf.Asia 2014)
Upcoming SlideShare
Loading in …5
×

Building Isomorphic Apps (JSConf.Asia 2014)

8,764 views

Published on

Over the past year or so, we’ve seen the emergence of a new way of building JavaScript web apps that share code between the web browser and the server, using Node.js — a technique that has come to be known as "isomorphic JavaScript.” There are a variety of use cases for isomorphic JavaScript; some apps render HTML on both the server and the client, some apps share just a few small bits of application logic, while others share the entire application runtime between client and server to provide advanced offline and realtime features. Why go isomorphic? The main benefits are performance, maintainability, reusability, and SEO.

This talk shares examples of isomorphic JavaScript apps running in the wild, explore the exploding ecosystem of asset building tools, such as Browserify, Webpack, and Gulp, that allow developers to build their own isomorphic JavaScript apps with open-source libraries, demonstrate how to build an isomorphic JavaScript module from scratch, and explore how libraries like React and Flux can be used to build a single-page app that renders on the server.

Published in: Technology
  • Be the first to comment

Building Isomorphic Apps (JSConf.Asia 2014)

  1. 1. Building Isomorphic Apps @spikebrehm
  2. 2. Spike Brehm ____________________________ @spikebrehm @AirbnbNerds
  3. 3. 1. Why Isomorphic JavaScript 2. Isomorphic in the Wild 3. How to Isomorph
  4. 4. Why Isomorphic JavaScript
  5. 5. What is Isomorphic JavaScript?
  6. 6. JavaScript code that can be shared between environments.
  7. 7. i·so·mor·phic same form
  8. 8. http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/
  9. 9. Persistence Client DOM manipulation UX JavaScript View layer Application logic Routing Backend Ruby Python Java PHP Ye Olde Web App
  10. 10. Backend Ruby Python Java PHP Fat-Client, circa 2011 Persistence Client DOM manipulation UX JavaScript View layer Application logic Routing
  11. 11. DOM manipulation UX Persistence Client JavaScript Shared JavaScript View layer Application logic Routing Backend Ruby Python Java PHP Isomorphic, circa 2013
  12. 12. Shared View Layer
  13. 13. DOM manipulation UX Persistence Client JavaScript Shared JavaScript View layer Application logic Routing Backend Ruby Python Java PHP Isomorphic, circa 2013
  14. 14. View layer
  15. 15. Markup Data presentation I18n Date, Currency formatting URL formatting
  16. 16. Isomorphic Use Cases 1. “Single Page Apps” that can be fully rendered on the server. 2. Ambitious apps that share logic between client & server to accomplish novel things.
  17. 17. Why go to the trouble?
  18. 18. Performance Initial pageload speed. SEO* Crawlable single-page apps. Flexibility Run code anywhere. Maintainability Reduce code duplication.
  19. 19. Performance
  20. 20. Client-rendered app Download skeleton HTML User sees content Download JavaScript Fetch data from API Evaluate JavaScript Exacerbated on mobile: high latency, low bandwidth
  21. 21. Server-rendered app Download full HTML Download JavaScript User sees content Evaluate JavaScript
  22. 22. Isomorphic JavaScript in the Wild
  23. 23. Flickr ! Yahoo’s Modown libraries (successor to Mojito).
  24. 24. Instagram* ! Facebook’s React library in a Django app.
  25. 25. Airbnb Mobile Web ! Airbnb’s Rendr library, built on Backbone and Express.
  26. 26. Asana ! Entire App runtime synced between client & server.
  27. 27. Meteor ! Realtime app framework.
  28. 28. Isomorphic JavaScript is a spectrum
  29. 29. Entire view layer and app logic shared Small bits of view layer or logic shared
  30. 30. Many abstractions Few abstractions
  31. 31. How to Isomorph
  32. 32. Isomorphic JavaScript can be environment agnostic or shimmed per environment.
  33. 33. Environment agnostic Does not depend on browser-specific properties (window) or server-specific properties (process.env, req.cookies).
  34. 34. E X A M P L E Handlebars.js var template = ! '<ul>' ! '{{#each posts}}' ! ' <li>{{title}}</li>' ! '{{/each}}' ! '</ul>';! ! var templateFn = Handlebars.compile(template);! var html = templateFn({posts: posts});
  35. 35. Shimmed per environment Provide shims for accessing environment-specific properties so module can expose a single API. window.location.pathname vs req.path
  36. 36. E X A M P L E Superagent superagent! .get('/api/posts.json')! .end(function(res) {! console.log(res.status, res.body, res.headers);! });
  37. 37. Abstractions
  38. 38. A B S T R ACT I O N Cookies Client document.cookie =! 'myCookie=1; Domain=.example.org'; Server res.setHeader(! 'Set-Cookie: myCookie=1; ' +! 'Domain=.example.org'! );
  39. 39. A B S T R ACT I O N Redirects Client document.location.href = '/login';! ! window.pushState({}, '', '/login'); Server res.redirect('/login');
  40. 40. H AC K T I M E Let’s write a module that abstracts the setting of cookies, providing the same API for client & server.
  41. 41. H AC K T I M E setCookie('myCookie', 'the value'); document.cookie = 'myCookie=the%20value'; or res.setHeader('Set-Cookie: myCookie=the%20value;');
  42. 42. H AC K T I M E 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';
  43. 43. That looks kinda hard…
  44. 44. NPM & Browserify* to the rescue
  45. 45. Browserify* Use CommonJS to require() modules in the browser.
  46. 46. Browserify* Package dependencies from node_modules into our bundle.
  47. 47. *or Webpack. Webpack is like Browserify, but with more bells-and- whistles included by default. Used by Instagram, Facebook, Yahoo!.
  48. 48. H AC K T I M E Caveat: It’s Different on the Server app.use(function(req, res, next) {! ...! ! next();! }); ! setCookie('myCookie', 'the value', {res: res});! ! ! !
  49. 49. How do we make a shimmed-per-environment module? Utilize package.json’s “browser” field.
  50. 50. {! "name": "set-cookie",! "dependencies": {...}! }! ! ! !
  51. 51. {! "name": "set-cookie",! "dependencies": {...},! "browser": "./lib/client.js"! }! ! ! Swap out the entire implementation.
  52. 52. {! "name": "set-cookie",! "dependencies": {...},! "browser": {! "./lib/node.js": "./lib/client.js"! }! }! Swap out specific files.
  53. 53. {! "name": "set-cookie",! "dependencies": {...},! "browser": {! "./lib/node.js": "./lib/client.js",! "cookie": "cookie-browser"! }! } Swap out dependencies.
  54. 54. Let’s build `set-cookie`. https://github.com/spikebrehm/set-cookie
  55. 55. Module structure .! "## index.js! "## lib! $ %## setter! $ "## index.js! $ %## client.js! "## node_modules! $ %## cookie
  56. 56. // ./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);! };
  57. 57. // ./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);! };
  58. 58. // ./lib/setter/client.js! ! module.exports = function setter(cookieStr) {! document.cookie = cookieStr;! };
  59. 59. // ./package.json! ! {! "name": "set-cookie",! "dependencies": {! "cookie": "^0.1.2"! },! "browser": {! "./lib/setter/index.js": "./lib/setter/client.js"! }! }
  60. 60. // ./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);! };
  61. 61. Projects of Note
  62. 62. React Reactive UI component library from Facebook. Designed from the ground up to support isomorphic rendering. http://facebook.github.io/react/ var UserProfile = React.createClass({ render: function() { return <div> <img src={this.props.user.thumbnailUrl} /> <h3>{this.props.user.name}</h3> </div>; } }); React.render(<UserProfile user={user} />, mountNode);
  63. 63. React Reactive UI component library from Facebook. Designed from the ground up to support isomorphic rendering. http://facebook.github.io/react/ var UserProfile = React.createClass({ render: function() { return <div> <img src={this.props.user.thumbnailUrl} /> <h3>{this.props.user.name}</h3> </div>; } }); React.render(<UserProfile user={user} />, mountNode);
  64. 64. React Reactive UI component library from Facebook. Designed from the ground up to support isomorphic rendering. http://facebook.github.io/react/ var UserProfile = React.createClass({ render: function() { return <div> <img src={this.props.user.thumbnailUrl} /> <h3>{this.props.user.name}</h3> </div>; } }); var html = React.renderToString(<UserProfile user={user} />);
  65. 65. Fluxible Yahoo’s isomorphic Flux implementation: Dispatchr, Fetchr, Routr. Provides a way to “dehydrate” server state and “rehydrate” on client. https://github.com/yahoo/flux-examples
  66. 66. Isobuild Meteor’s build system for isomorphic apps. Like Browserify & Webpack, uses static analysis to compute dependencies. Can target client, server, Android, or iOS. https://www.meteor.com/isobuild if (Meteor.isClient) { // counter starts at 0 Session.setDefault("counter", 0); Template.hello.events({ 'click button': function () { // increment the counter when button is clicked Session.set("counter", Session.get("counter") + 1); } }); } if (Meteor.isServer) { Meteor.startup(function () { // code to run on server at startup }); }
  67. 67. Isobuild Meteor’s build system for isomorphic apps. Like Browserify & Webpack, uses static analysis to compute dependencies. Can target client, server, Android, or iOS. https://www.meteor.com/isobuild if (Meteor.isClient) { // counter starts at 0 Session.setDefault("counter", 0); Template.hello.events({ 'click button': function () { // increment the counter when button is clicked Session.set("counter", Session.get("counter") + 1); } }); } if (Meteor.isServer) { Meteor.startup(function () { // code to run on server at startup }); }
  68. 68. isomorphic-tutorial Small sample isomorphic app, written from scratch using Handlebars/ React, Director (routing), and Superagent (API requests). https://github.com/spikebrehm/isomorphic-tutorial // app/routes.js var apiClient = require('./api_client'); module.exports = function(match) { match('/posts', function(callback) { apiClient.get('/posts.json', function(err, res) { if (err) return callback(err); var posts = res.body; callback(null, 'posts', {posts: posts}); }); }); };
  69. 69. isomorphic-tutorial Small sample isomorphic app, written from scratch using Handlebars/ React, Director (routing), and Superagent (API requests). https://github.com/spikebrehm/isomorphic-tutorial <h1>Posts</h1> <ul> {{#each posts}} <li><a href="/posts/{{id}}">{{title}}</a></li> {{/each}} </ul>
  70. 70. Thanks! More resources available at http://spike.technology ! @spikebrehm @AirbnbNerds

×