building isomorphic apps (jsconf.asia 2014)

71
Building Isomorphic Apps @spikebrehm

Upload: spike-brehm

Post on 02-Jul-2015

5.662 views

Category:

Technology


0 download

DESCRIPTION

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.

TRANSCRIPT

Page 1: Building Isomorphic Apps (JSConf.Asia 2014)

Building Isomorphic Apps @spikebrehm

Page 2: Building Isomorphic Apps (JSConf.Asia 2014)

Spike Brehm ____________________________

@spikebrehm

@AirbnbNerds

Page 3: Building Isomorphic Apps (JSConf.Asia 2014)

1. Why Isomorphic JavaScript 2. Isomorphic in the Wild 3. How to Isomorph

Page 4: Building Isomorphic Apps (JSConf.Asia 2014)

Why Isomorphic JavaScript

Page 5: Building Isomorphic Apps (JSConf.Asia 2014)

What is Isomorphic JavaScript?

Page 6: Building Isomorphic Apps (JSConf.Asia 2014)

JavaScript code that can be shared between environments.

Page 7: Building Isomorphic Apps (JSConf.Asia 2014)

i·so·mor·phicformsame

Page 8: Building Isomorphic Apps (JSConf.Asia 2014)

http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/

Page 9: Building Isomorphic Apps (JSConf.Asia 2014)

Persistence

Client JavaScriptDOM manipulation UX

View layerApplication

logic Routing

Backend Ruby

Python Java PHP

Ye Olde Web App

Page 10: Building Isomorphic Apps (JSConf.Asia 2014)

Backend Ruby

Python Java PHP

Persistence

Client JavaScriptDOM manipulation UX

View layerApplication

logic Routing

Fat-Client, circa 2011

Page 11: Building Isomorphic Apps (JSConf.Asia 2014)

Persistence

Client JavaScript

Shared JavaScript

View layerApplication

logic Routing

DOM manipulation UX

Backend Ruby

Python Java PHP

Isomorphic, circa 2013

Page 12: Building Isomorphic Apps (JSConf.Asia 2014)

Shared View Layer

Page 13: Building Isomorphic Apps (JSConf.Asia 2014)

Persistence

Client JavaScript

Shared JavaScript

View layerApplication

logic Routing

DOM manipulation UX

Backend Ruby

Python Java PHP

Isomorphic, circa 2013

Page 14: Building Isomorphic Apps (JSConf.Asia 2014)

View layer

Page 15: Building Isomorphic Apps (JSConf.Asia 2014)

Markup

Data presentation

URL formatting

Date, Currency formatting

I18n

Page 16: Building Isomorphic Apps (JSConf.Asia 2014)

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.

Page 17: Building Isomorphic Apps (JSConf.Asia 2014)

Why go to the trouble?

Page 18: Building Isomorphic Apps (JSConf.Asia 2014)

PerformanceInitial pageload speed.

SEO*Crawlable single-page apps.

FlexibilityRun code anywhere.

MaintainabilityReduce code duplication.

Page 19: Building Isomorphic Apps (JSConf.Asia 2014)

Performance

Page 20: Building Isomorphic Apps (JSConf.Asia 2014)

Client-rendered appDownload skeleton HTML

User sees content

Download JavaScript

Fetch data from API

Evaluate JavaScript

Exacerbated on mobile: high latency, low bandwidth

Page 21: Building Isomorphic Apps (JSConf.Asia 2014)

Server-rendered appDownload

full HTML

Download JavaScript

User sees content

Evaluate JavaScript

Page 22: Building Isomorphic Apps (JSConf.Asia 2014)

Isomorphic JavaScript in the Wild

Page 23: Building Isomorphic Apps (JSConf.Asia 2014)

! Yahoo’s Modown libraries (successor to Mojito).

Flickr

Page 24: Building Isomorphic Apps (JSConf.Asia 2014)

! Facebook’s React library in a Django app.

Instagram*

Page 25: Building Isomorphic Apps (JSConf.Asia 2014)

! Airbnb’s Rendr library, built on Backbone and Express.

Airbnb Mobile Web

Page 26: Building Isomorphic Apps (JSConf.Asia 2014)

! Entire App runtime synced between client & server.

Asana

Page 27: Building Isomorphic Apps (JSConf.Asia 2014)

! Realtime app framework. Meteor

Page 28: Building Isomorphic Apps (JSConf.Asia 2014)

Isomorphic JavaScript is a spectrum

Page 29: Building Isomorphic Apps (JSConf.Asia 2014)

Entire view layer and app

logic shared

Small bits of view layer or logic shared

Page 30: Building Isomorphic Apps (JSConf.Asia 2014)

Many abstractions

Few abstractions

Page 31: Building Isomorphic Apps (JSConf.Asia 2014)

How to Isomorph

Page 32: Building Isomorphic Apps (JSConf.Asia 2014)

Isomorphic JavaScript can beenvironment agnostic

orshimmed per environment.

Page 33: Building Isomorphic Apps (JSConf.Asia 2014)

Environment agnostic

Does not depend on browser-specific properties (window) or server-specific properties (process.env, req.cookies).

Page 34: Building Isomorphic Apps (JSConf.Asia 2014)

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});

Page 35: Building Isomorphic Apps (JSConf.Asia 2014)

Shimmed per environment

Provide shims for accessing environment-specific properties so module can expose a single API.

window.location.pathnamevs req.path

Page 36: Building Isomorphic Apps (JSConf.Asia 2014)

E X A M P L E

Superagent

superagent! .get('/api/posts.json')! .end(function(res) {! console.log(res.status, res.body, res.headers);! });

Page 37: Building Isomorphic Apps (JSConf.Asia 2014)

Abstractions

Page 38: Building Isomorphic Apps (JSConf.Asia 2014)

A B S T R A C T I O N

Cookies

Client document.cookie =! 'myCookie=1; Domain=.example.org';

Server res.setHeader(! 'Set-Cookie: myCookie=1; ' +! 'Domain=.example.org'! );

Page 39: Building Isomorphic Apps (JSConf.Asia 2014)

A B S T R A C T I O N

Redirects

Clientdocument.location.href = '/login';!

!window.pushState({}, '', '/login');

Server res.redirect('/login');

Page 40: Building Isomorphic Apps (JSConf.Asia 2014)

Let’s write a module that abstracts the setting of cookies, providing the same API for client & server.

H A C K T I M E

Page 41: Building Isomorphic Apps (JSConf.Asia 2014)

H A C K T I M E

setCookie('myCookie', 'the value');

document.cookie = 'myCookie=the%20value';

or

res.setHeader('Set-Cookie: myCookie=the%20value;');

Page 42: Building Isomorphic Apps (JSConf.Asia 2014)

H A C 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';

Page 43: Building Isomorphic Apps (JSConf.Asia 2014)

That looks kinda hard…

Page 44: Building Isomorphic Apps (JSConf.Asia 2014)
Page 45: Building Isomorphic Apps (JSConf.Asia 2014)

NPM & Browserify* to the rescue

Page 46: Building Isomorphic Apps (JSConf.Asia 2014)

Browserify* Use CommonJS to require() modules in the browser.

Page 47: Building Isomorphic Apps (JSConf.Asia 2014)

Browserify* Package dependencies from node_modules into our bundle.

Page 48: Building Isomorphic Apps (JSConf.Asia 2014)

*or Webpack.

Webpack is like Browserify, but with more bells-and-whistles included by default.

Used by Instagram, Facebook, Yahoo!.

Page 49: Building Isomorphic Apps (JSConf.Asia 2014)

H A C K T I M E

Caveat: It’s Different on the Server

! setCookie('myCookie', 'the value', {res: res});!!!!

app.use(function(req, res, next) {! setCookie('myCookie', 'the value', {res: res});! ...!! next();!});

Page 50: Building Isomorphic Apps (JSConf.Asia 2014)

How do we make a shimmed-per-environment module?

Utilize package.json’s “browser” field.

Page 51: Building Isomorphic Apps (JSConf.Asia 2014)

{! "name": "set-cookie",! "dependencies": {...}!}!!!!

Page 52: Building Isomorphic Apps (JSConf.Asia 2014)

Swap out the entire implementation.

{! "name": "set-cookie",! "dependencies": {...},! "browser": "./lib/client.js"!}!!!

Page 53: Building Isomorphic Apps (JSConf.Asia 2014)

Swap out specific files.

{! "name": "set-cookie",! "dependencies": {...},! "browser": {! "./lib/node.js": "./lib/client.js"! }!}!

Page 54: Building Isomorphic Apps (JSConf.Asia 2014)

Swap out dependencies.

{! "name": "set-cookie",! "dependencies": {...},! "browser": {! "./lib/node.js": "./lib/client.js",! "cookie": "cookie-browser"! }!}

Page 55: Building Isomorphic Apps (JSConf.Asia 2014)

Let’s build `set-cookie`.

https://github.com/spikebrehm/set-cookie

Page 56: Building Isomorphic Apps (JSConf.Asia 2014)

Module structure

.!"## index.js!"## lib!$   %## setter!$   "## index.js!$   %## client.js!"## node_modules!$   %## cookie

Page 57: Building Isomorphic Apps (JSConf.Asia 2014)

// ./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);!};

Page 58: Building Isomorphic Apps (JSConf.Asia 2014)

// ./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);!};

Page 59: Building Isomorphic Apps (JSConf.Asia 2014)

// ./lib/setter/client.js!!module.exports = function setter(cookieStr) {!  document.cookie = cookieStr;!};

Page 60: Building Isomorphic Apps (JSConf.Asia 2014)

// ./package.json!!{! "name": "set-cookie",! "dependencies": {! "cookie": "^0.1.2"! },! "browser": {! "./lib/setter/index.js": "./lib/setter/client.js"! }!}

Page 61: Building Isomorphic Apps (JSConf.Asia 2014)

// ./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);!};

Page 62: Building Isomorphic Apps (JSConf.Asia 2014)

Projects of Note

Page 63: Building Isomorphic Apps (JSConf.Asia 2014)

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);

Page 64: Building Isomorphic Apps (JSConf.Asia 2014)

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);

React Reactive UI component library from Facebook. Designed from the ground up to support isomorphic rendering. http://facebook.github.io/react/

Page 65: Building Isomorphic Apps (JSConf.Asia 2014)

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} />);

React Reactive UI component library from Facebook. Designed from the ground up to support isomorphic rendering. http://facebook.github.io/react/

Page 66: Building Isomorphic Apps (JSConf.Asia 2014)

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

Page 67: Building Isomorphic Apps (JSConf.Asia 2014)

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 }); }

Page 68: Building Isomorphic Apps (JSConf.Asia 2014)

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 }); }

Page 69: Building Isomorphic Apps (JSConf.Asia 2014)

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}); }); }); };

Page 70: Building Isomorphic Apps (JSConf.Asia 2014)

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>

Page 71: Building Isomorphic Apps (JSConf.Asia 2014)

Thanks! More resources available at

http://spike.technology !

@spikebrehm @AirbnbNerds