Upload
spike-brehm
View
2.674
Download
0
Tags:
Embed Size (px)
DESCRIPTION
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.
Citation preview
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 Application logic Routing
Etymology of “Isomorphic JavaScript”.
adjective corresponding or similar in form and relations.
i·so·mor·phic
i·so·mor·phicformsame
http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/
“monomorphic” “heteromorphic” “homomorphic” “polymorphic”
You’re using it wrong!
Isomorphic JavaScript in the wild.
! Yahoo’s Modown libraries Flickr
! Yahoo’s Modown libraries Flickr
! Yahoo’s Modown libraries (successor to Mojito).
Flickr
! Facebook’s React library Instagram*
! Facebook’s React library Instagram*
! Facebook’s React library in a Django app.
Instagram*
! Airbnb’s Rendr library, built on Airbnb Mobile
! Airbnb’s Rendr library, built on Airbnb Mobile
! Airbnb’s Rendr library, built on Backbone and Express.
Airbnb Mobile
! Entire App runtime synced Asana
! Entire App runtime synced between client & server.
Asana
! Realtime app framework. Meteor
! Realtime app framework. Meteor
Wy go to the trouble?
Initial pageload speed.Performance
Crawlable single-page apps.SEO*
Reduce code duplication.MaintainabilityRun code anywhere.Flexibility
Isomorphic use cases.
• Templating • I18n • Date & currency formatting • Application logic • Routing • Model validation • API interaction • ...?
Isomorphic use cases.
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).
Environment-agnostic
Example: Handlebars.js
var template = ! '<ul>' \! '{{#each posts}}' \! ' <li>{{title}}</li>' \! '{{/each}}' \! '</ul>'!;! !var templateFn = Handlebars.compile(template)! , html = templateFn({posts: posts});
Provide shims for accessing environment-specific properties so module can expose a single API.
window.location.pathnamevs. req.path
Shimmed per environment
Example: Superagent
superagent! .get('/api/posts.json')! .end(function(res) {! if (res.status === 200) {! console.log("Posts:", res.body);! } else {! console.error("Error");! }! });
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: myCookie=1; ' +! 'Domain=.example.org'! );
Abstraction: Redirects
Clientdocument.location.href = '/login';!
!window.pushState({}, '', '/login');
Server res.redirect('/login');
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%20value;');
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';
Eww, that looks hard.
NPM & Browserify to the rescue.
BrowserifyUse CommonJS to require() modules in the browser.
BrowserifyPackage 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 files.
{! "name": "set-cookie",! "dependencies": {...},! "browser": {! "./lib/node.js": "./lib/client.js",! "cookie": "cookie-browser"! }!}
Swap out dependencies.
Let’s build `set-cookie`.https://github.com/spikebrehm/set-cookie
Module structure.!"## index.js!"## lib!$ %## setter!$ "## index.js!$ %## client.js!"## node_modules!$ %## cookie
// ./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);!};
// ./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);!};
// ./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/index.js": "./lib/setter/client.js"! }!}
// ./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);!};
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 hiring!!!We’re hiring!!!We’re hiring!!!We’re hiring!!!