SlideShare a Scribd company logo
1 of 82
Download to read offline
Introducing Rendr:
Run your Backbone.js apps
on the client and server

Spike Brehm
@spikebrehm

HTML5DevConf
April 1, 2013
2008
2013
Exciting times in the
world of web apps.


<your framework here>
Client-side
MVC
+
Poor SEO; not crawlable
Performance hit to download
and parse JS
Duplicated application logic
Context switching
It’s still a PITA to build
fast, maintainable
rich-client apps.
We started thinking...

What if our JavaScript
app could run on both
sides?
Client +
server
MVC
aka “The Holy Grail”
Provides SEO
Initial pageload is drastically
faster
Consolidated application logic
Has anyone already
done this?
Meteor: client/server, but no
server-side rendering; owns data
layer
Derby: client+server rendering,
but owns data layer
Mojito: client+server rendering,
but full stack, and... YUI.
Okay... how hard can
it be?
+
+
Rendr.
What it is.
What it is.
JavaScript MVC on client & server
Backbone & Handlebars
BaseView, BaseModel,
BaseCollection, BaseApp,
ClientRouter, ServerRouter...
Express middleware
Minimal glue between client & server
What it ain’t.
What it ain’t.

Batteries-included web framework
Finished
Design goals:
•   Write application logic agnostic to
    environment.
•   Library, not a framework.
•   Minimize   if (server) {...} else {...}.

•   Hide complexity in library.
•   Talk to RESTful API.
•   No server-side DOM.
•   Simple Express middleware.
Classes:
- BaseApp < Backbone.Model
- BaseModel < Backbone.Model
- BaseCollection < Backbone.Collection
- BaseView < Backbone.View
- AppView < BaseView
- ClientRouter < BaseRouter
- ServerRouter < BaseRouter
- ModelStore < MemoryStore
- CollectionStore < MemoryStore
- Fetcher
Rendr directory structure
|- client/
|- shared/   } Sent to client
|- server/
App directory structure
|- app/
|- public/
|- server/
App directory structure




                    }
|- app/
|--- collections/
|--- controllers/
|--- models/            Entire app dir
|--- templates/         gets sent to
|--- views/
|--- app.js
                        client
|--- router.js
|--- routes.js
|- public/
|- server/
CommonJS using Stitch

On the server:
var User = require(‘app/models/user’);
var BaseView = require(‘rendr/shared/base/view’);


On the client:
var User = require(‘app/models/user’);
var BaseView = require(‘rendr/shared/base/view’);
app/routes.js


 module.exports = function(match) {
    match('',          'home#index');
    match('users',     'users#index');
    match('users/:id', 'users#show');
 };
app/routes.js


 module.exports = function(match) {
    match('',          'home#index');
    match('users',     'users#index');
    match('users/:id', 'users#show');
 };


                     controller
app/routes.js


 module.exports = function(match) {
    match('',          'home#index');
    match('users',     'users#index');
    match('users/:id', 'users#show');
 };


                        action
Render lifecycle,
server.
•   On server startup, parse routes file and mount as
    Express routes
•   GET /users/1337
•   Router matches "/users/:id" to "users#show" with
    params = {"id": 1337}
•   Router finds controller:
    require("app/controllers/users_controller")
•   Router executes show action with params = {"id": 1337}
•   The show action says to fetch User#1337 and use
    UsersShowView view class
•   Router instantiates new UsersShowView with data
•   Router calls view.getHtml()
•   Hands HTML to Express, which decorates with layout
    and serves response
Render lifecycle,
client.
•   On page load, Router parses routes file and mounts
    Backbone routes
•   pushState /users/1337
•   Router matches "/users/:id" to "users#show" with
    params = {"id": 1337}
•   Router finds controller:
    require("app/controllers/users_controller")
•   Router executes show action with params = {"id": 1337}
•   The show action says to fetch User#1337 and use
    UsersShowView view class
•   Router instantiates new UsersShowView with data
•   Router calls view.render()
•   Insert into DOM
•   On page load, Router parses routes file and mounts
    Backbone routes
•   pushState /users/1337
•   Router matches "/users/:id" to "users#show" with
    params = {"id": 1337}
•   Router finds controller:
    require("app/controllers/users_controller")
•   Router executes show action with params = {"id": 1337}
•   The show action says to fetch User#1337 and use
    UsersShowView view class
•   Router instantiates new UsersShowView with data
•   Router calls view.render()
•   Insert into DOM
•   On page load, Router parses routes file and mounts
    Backbone routes
•   pushState /users/1337
•   Router matches "/users/:id" to "users#show" with
    params = {"id": 1337}
•   Router finds controller:
    require("app/controllers/users_controller")
•   Router executes show action with params = {"id": 1337}
•   The show action says to fetch User#1337 and use
    UsersShowView view class
•   Router instantiates new UsersShowView with data
•   Router calls view.render()
•   Insert into DOM
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     callback(null, 'users_show_view');
   }
};
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     callback(null, 'users_show_view');
   }
};
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     callback(null, 'users_show_view');
   }
};
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     callback(null, 'users_show_view');
   }
};
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     callback(null, 'users_show_view');
   }
};




Most simple case: no fetching of
data.
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     callback(null, 'users_show_view');
   }
};




But we want to fetch the user.
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     var spec = {
        model: {model: ‘User’, params: params}
     };
     this.app.fetch(spec, function(err, results) {
        callback(err, 'users_show_view', results);
     });
   }
};
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     var spec = {
        model: {model: ‘User’, params: params}
     };
     this.app.fetch(spec, function(err, results) {
        callback(err, 'users_show_view', results);
     });
   }
};
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     var spec = {
        model: {model: ‘User’, params: params}
     };
     this.app.fetch(spec, function(err, results) {
        callback(err, 'users_show_view', results);
     });
   }
};
app/controllers/users_controller.js

module.exports = {
   show: function(params, callback) {
     var spec = {
        model: {model: ‘User’, params: params}
     };
     this.app.fetch(spec, function(err, results) {
        callback(err, 'users_show_view', results);
     });
   }
};
app/views/users_show_view.js

var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view'
});
module.exports.id = 'users_show_view';
app/views/users_show_view.js

var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view'
});
module.exports.id = 'users_show_view';
app/views/users_show_view.js

var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view'
});
module.exports.id = 'users_show_view';
app/views/users_show_view.js

var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view'
});
module.exports.id = 'users_show_view';
app/views/users_show_view.js

var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view',

  events: {
   'click p': 'handleClick'
  },

  handleClick: function() {...}
});
module.exports.id = 'users_show_view';
app/templates/users_show_view.hbs



<h1>User: {{name}}</h1>

<p>From {{city}}.</p>
Rendered HTML

<div class="users_show_view"
     data-view="users_show_view"
     data-model_name="user"
     data-model_id="1337">

  <h1>User: Spike</h1>

  <p>From San Francisco.</p>
</div>
Rendered HTML

<div class="users_show_view"
     data-view="users_show_view"
     data-model_name="user"
     data-model_id="1337">

  <h1>User: Spike</h1>

  <p>From San Francisco.</p>
</div>
Rendered HTML

<div class="users_show_view"
     data-view="users_show_view"
     data-model_name="user"
     data-model_id="1337">

  <h1>User: Spike</h1>

  <p>From San Francisco.</p>
</div>
Rendered HTML

<div class="users_show_view"
     data-view="users_show_view"
     data-model_name="user"
     data-model_id="1337">

  <h1>User: Spike</h1>

  <p>From San Francisco.</p>
</div>
Where’d the data come from?
Where’s the render method?
How do I customize what gets
passed to the template?
Sensible defaults.
app/views/users_show_view.js
var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view',

  getTemplateData: function() {

  }
});
app/views/users_show_view.js
var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view',

  getTemplateData: function() {
    var data = BaseView.prototype.getTemplateData 
      .call(this);
  }
});
app/views/users_show_view.js
var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view',

  getTemplateData: function() {
    var data = BaseView.prototype.getTemplateData 
      .call(this);
    // `data` is equivalent to this.model.toJSON()

  }
});
app/views/users_show_view.js
var BaseView = require('rendr/shared/base/view');

module.exports = BaseView.extend({
  className: 'users_show_view',

  getTemplateData: function() {
    var data = BaseView.prototype.getTemplateData 
      .call(this);
    // `data` is equivalent to this.model.toJSON()
    return _.extend(data, {
      nameUppercase: data.name.toUpperCase()
    });
  }
});
app/templates/users_show_view.hbs



<h1>User: {{nameUppercase}}</h1>

<p>From {{city}}.</p>
Rendered HTML


<div class="users_show_view" data-...>
  <h1>User: SPIKE</h1>

  <p>From San Francisco.</p>
</div>
Rendered HTML with layout
<!doctype html>
<html lang="en">
<head>...</head>

<body>
<div id="content">
  <div class="users_show_view" data-view="users_show_view"
       data-model_name="user" data-model_id="1337">

    <h1>User: SPIKE</h1>

    <p>From San Francisco.</p>
  </div>
</div>

<script>
(function() {
var App = window.App = new (require('app/app'));
App.bootstrapData({
  "model":{"summary":{"model":"user","id":1337},
  "data":{"name":"Spike","city":"San Francisco", ...}
});
App.start();
})();
</script>
</body></html>
Rendered HTML with layout
<!doctype html>
<html lang="en">
<head>...</head>

<body>
<div id="content">
  <div class="users_show_view" data-view="users_show_view"
       data-model_name="user" data-model_id="1337">

    <h1>User: SPIKE</h1>

    <p>From San Francisco.</p>
  </div>
</div>

<script>
(function() {
var App = window.App = new (require('app/app'));
App.bootstrapData({
  "model":{"summary":{"model":"user","id":"wycats"},
  "data":{"name":"Spike","city":"San Francisco", ...}
});
App.start();
})();
</script>
</body></html>
View hydration.
1. Find DOM els with data-view attribute.
var viewEls = $("[data-view]");
2. Determine model or collection based on
data-model_name, data-model_id, etc.

var modelName = viewEl.data(‘model_name’),
    modelId   = viewEl.data(‘model_id’);

console.log(modelName, modelId);
 => “user” 1337
3. Fetch model/collection data from
ModelStore/CollectionStore.
var model = modelStore.get(modelName,
              modelId);
4. Find view class.
var viewName, ViewClass;
viewName = viewEl.data(‘view’);
ViewClass = require('app/views/' + viewName);
5. Instantiate view instance with model.
var view = new ViewClass({
  model: model,
  ...
});
6. Attach to DOM el.
view.setElement(viewEl);
7. Delegate events.
view.delegateEvents();
8. Profit!
alert(“That wasn’t so hard, right?”)
Rendr is available
starting today.
github.com/airbnb/rendr
TODO

•   Share routing logic between client &
    server.

•   Lazy load views, templates, etc as needed.

•   Support other templating languages.

•   Break down into smaller modules.

•   Rewrite in vanilla JavaScript.

•   much more...
Hackers
wanted.
Thanks!
@spikebrehm
  @rendrjs
@AirbnbNerds

More Related Content

What's hot

Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점Jeado Ko
 
How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0Takuya Tejima
 
Modern Web Application Development Workflow - EclipseCon Europe 2014
Modern Web Application Development Workflow - EclipseCon Europe 2014Modern Web Application Development Workflow - EclipseCon Europe 2014
Modern Web Application Development Workflow - EclipseCon Europe 2014Stéphane Bégaudeau
 
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...Atlassian
 
Managing JavaScript Dependencies With RequireJS
Managing JavaScript Dependencies With RequireJSManaging JavaScript Dependencies With RequireJS
Managing JavaScript Dependencies With RequireJSDen Odell
 
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...Atlassian
 
Refactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.jsRefactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.jsStacy London
 
An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications Rohan Chandane
 
Planbox Backbone MVC
Planbox Backbone MVCPlanbox Backbone MVC
Planbox Backbone MVCAcquisio
 
Javascript Frameworks for Well Architected, Immersive Web Apps
Javascript Frameworks for Well Architected, Immersive Web AppsJavascript Frameworks for Well Architected, Immersive Web Apps
Javascript Frameworks for Well Architected, Immersive Web Appsdnelson-cs
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIVisual Engineering
 
Getting Started with Angular JS
Getting Started with Angular JSGetting Started with Angular JS
Getting Started with Angular JSAkshay Mathur
 
AngularJS 101 - Everything you need to know to get started
AngularJS 101 - Everything you need to know to get startedAngularJS 101 - Everything you need to know to get started
AngularJS 101 - Everything you need to know to get startedStéphane Bégaudeau
 
MVC on the server and on the client
MVC on the server and on the clientMVC on the server and on the client
MVC on the server and on the clientSebastiano Armeli
 

What's hot (20)

Vue, vue router, vuex
Vue, vue router, vuexVue, vue router, vuex
Vue, vue router, vuex
 
Angular js
Angular jsAngular js
Angular js
 
Vuex
VuexVuex
Vuex
 
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
 
How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0
 
Modern Web Application Development Workflow - EclipseCon Europe 2014
Modern Web Application Development Workflow - EclipseCon Europe 2014Modern Web Application Development Workflow - EclipseCon Europe 2014
Modern Web Application Development Workflow - EclipseCon Europe 2014
 
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...
No Coding Necessary: Building Confluence User Macros Cheat Sheet - Atlassian ...
 
Managing JavaScript Dependencies With RequireJS
Managing JavaScript Dependencies With RequireJSManaging JavaScript Dependencies With RequireJS
Managing JavaScript Dependencies With RequireJS
 
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...
No Coding Necessary: Building User Macros and Dynamic Reports Inside Confluen...
 
Refactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.jsRefactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.js
 
An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications
 
Introduction to Angularjs
Introduction to AngularjsIntroduction to Angularjs
Introduction to Angularjs
 
Planbox Backbone MVC
Planbox Backbone MVCPlanbox Backbone MVC
Planbox Backbone MVC
 
Javascript Frameworks for Well Architected, Immersive Web Apps
Javascript Frameworks for Well Architected, Immersive Web AppsJavascript Frameworks for Well Architected, Immersive Web Apps
Javascript Frameworks for Well Architected, Immersive Web Apps
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte II
 
Getting Started with Angular JS
Getting Started with Angular JSGetting Started with Angular JS
Getting Started with Angular JS
 
AngularJS 101 - Everything you need to know to get started
AngularJS 101 - Everything you need to know to get startedAngularJS 101 - Everything you need to know to get started
AngularJS 101 - Everything you need to know to get started
 
MVC on the server and on the client
MVC on the server and on the clientMVC on the server and on the client
MVC on the server and on the client
 
Spring MVC
Spring MVCSpring MVC
Spring MVC
 
Vue business first
Vue business firstVue business first
Vue business first
 

Similar to Introducing Rendr: Run your Backbone.js apps on the client and server

Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Eliran Eliassy
 
Building a dashboard using AngularJS
Building a dashboard using AngularJSBuilding a dashboard using AngularJS
Building a dashboard using AngularJSRajthilakMCA
 
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...OdessaJS Conf
 
Reactive application using meteor
Reactive application using meteorReactive application using meteor
Reactive application using meteorSapna Upreti
 
Aurelia Meetup Paris
Aurelia Meetup ParisAurelia Meetup Paris
Aurelia Meetup ParisAhmed Radjdi
 
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJSAngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJSmurtazahaveliwala
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJSGregor Woiwode
 
AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014
AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014
AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014FalafelSoftware
 
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page AppsOptimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page AppsMorgan Stone
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications Juliana Lucena
 
Angular js routing options
Angular js routing optionsAngular js routing options
Angular js routing optionsNir Kaufman
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basicsAnton Narusberg
 
Dundee University HackU 2013 - Mojito
Dundee University HackU 2013 - MojitoDundee University HackU 2013 - Mojito
Dundee University HackU 2013 - Mojitosmartads
 
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0Frost
 
Asp.Net Mvc
Asp.Net MvcAsp.Net Mvc
Asp.Net Mvcmicham
 
Building Web Apps with Express
Building Web Apps with ExpressBuilding Web Apps with Express
Building Web Apps with ExpressAaron Stannard
 

Similar to Introducing Rendr: Run your Backbone.js apps on the client and server (20)

Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics Angular server side rendering - Strategies & Technics
Angular server side rendering - Strategies & Technics
 
Building a dashboard using AngularJS
Building a dashboard using AngularJSBuilding a dashboard using AngularJS
Building a dashboard using AngularJS
 
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
 
Reactive application using meteor
Reactive application using meteorReactive application using meteor
Reactive application using meteor
 
Aurelia Meetup Paris
Aurelia Meetup ParisAurelia Meetup Paris
Aurelia Meetup Paris
 
Mini-Training: AngularJS
Mini-Training: AngularJSMini-Training: AngularJS
Mini-Training: AngularJS
 
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJSAngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
AngularJS training - Day 1 - Basics: Why, What and basic features of AngularJS
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJS
 
AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014
AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014
AngularJS in 60ish Minutes - Dan Wahlin | FalafelCON 2014
 
Optimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page AppsOptimizing Angular Performance in Enterprise Single Page Apps
Optimizing Angular Performance in Enterprise Single Page Apps
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
 
AngularJS
AngularJSAngularJS
AngularJS
 
Angular js routing options
Angular js routing optionsAngular js routing options
Angular js routing options
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
 
Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2
 
AngularJs-training
AngularJs-trainingAngularJs-training
AngularJs-training
 
Dundee University HackU 2013 - Mojito
Dundee University HackU 2013 - MojitoDundee University HackU 2013 - Mojito
Dundee University HackU 2013 - Mojito
 
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
Building an angular application -1 ( API: Golang, Database: Postgres) v1.0
 
Asp.Net Mvc
Asp.Net MvcAsp.Net Mvc
Asp.Net Mvc
 
Building Web Apps with Express
Building Web Apps with ExpressBuilding Web Apps with Express
Building Web Apps with Express
 

More from Spike Brehm

Managing Through Chaos (w/ presenter notes)
Managing Through Chaos (w/ presenter notes)Managing Through Chaos (w/ presenter notes)
Managing Through Chaos (w/ presenter notes)Spike Brehm
 
Managing Through Chaos
Managing Through ChaosManaging Through Chaos
Managing Through ChaosSpike Brehm
 
The Evolution of Airbnb's Frontend
The Evolution of Airbnb's FrontendThe Evolution of Airbnb's Frontend
The Evolution of Airbnb's FrontendSpike Brehm
 
Integrating Browserify with Sprockets
Integrating Browserify with SprocketsIntegrating Browserify with Sprockets
Integrating Browserify with SprocketsSpike Brehm
 
Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)Spike Brehm
 
JSConf US 2014: Building Isomorphic Apps
JSConf US 2014: Building Isomorphic AppsJSConf US 2014: Building Isomorphic Apps
JSConf US 2014: Building Isomorphic AppsSpike Brehm
 
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript AppsIn Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript AppsSpike Brehm
 
General Assembly Workshop: Advanced JavaScript
General Assembly Workshop: Advanced JavaScriptGeneral Assembly Workshop: Advanced JavaScript
General Assembly Workshop: Advanced JavaScriptSpike Brehm
 
Isomorphic JavaScript: #DevBeat Master Class
Isomorphic JavaScript: #DevBeat Master ClassIsomorphic JavaScript: #DevBeat Master Class
Isomorphic JavaScript: #DevBeat Master ClassSpike Brehm
 
Building a Single-Page App: Backbone, Node.js, and Beyond
Building a Single-Page App: Backbone, Node.js, and BeyondBuilding a Single-Page App: Backbone, Node.js, and Beyond
Building a Single-Page App: Backbone, Node.js, and BeyondSpike Brehm
 
Extending Apostrophe to build a variable-based CMS for rendering PDF brochures
Extending Apostrophe to build a variable-based CMS for rendering PDF brochuresExtending Apostrophe to build a variable-based CMS for rendering PDF brochures
Extending Apostrophe to build a variable-based CMS for rendering PDF brochuresSpike Brehm
 

More from Spike Brehm (11)

Managing Through Chaos (w/ presenter notes)
Managing Through Chaos (w/ presenter notes)Managing Through Chaos (w/ presenter notes)
Managing Through Chaos (w/ presenter notes)
 
Managing Through Chaos
Managing Through ChaosManaging Through Chaos
Managing Through Chaos
 
The Evolution of Airbnb's Frontend
The Evolution of Airbnb's FrontendThe Evolution of Airbnb's Frontend
The Evolution of Airbnb's Frontend
 
Integrating Browserify with Sprockets
Integrating Browserify with SprocketsIntegrating Browserify with Sprockets
Integrating Browserify with Sprockets
 
Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)Building Isomorphic Apps (JSConf.Asia 2014)
Building Isomorphic Apps (JSConf.Asia 2014)
 
JSConf US 2014: Building Isomorphic Apps
JSConf US 2014: Building Isomorphic AppsJSConf US 2014: Building Isomorphic Apps
JSConf US 2014: Building Isomorphic Apps
 
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript AppsIn Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
 
General Assembly Workshop: Advanced JavaScript
General Assembly Workshop: Advanced JavaScriptGeneral Assembly Workshop: Advanced JavaScript
General Assembly Workshop: Advanced JavaScript
 
Isomorphic JavaScript: #DevBeat Master Class
Isomorphic JavaScript: #DevBeat Master ClassIsomorphic JavaScript: #DevBeat Master Class
Isomorphic JavaScript: #DevBeat Master Class
 
Building a Single-Page App: Backbone, Node.js, and Beyond
Building a Single-Page App: Backbone, Node.js, and BeyondBuilding a Single-Page App: Backbone, Node.js, and Beyond
Building a Single-Page App: Backbone, Node.js, and Beyond
 
Extending Apostrophe to build a variable-based CMS for rendering PDF brochures
Extending Apostrophe to build a variable-based CMS for rendering PDF brochuresExtending Apostrophe to build a variable-based CMS for rendering PDF brochures
Extending Apostrophe to build a variable-based CMS for rendering PDF brochures
 

Recently uploaded

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 

Recently uploaded (20)

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 

Introducing Rendr: Run your Backbone.js apps on the client and server

  • 1. Introducing Rendr: Run your Backbone.js apps on the client and server Spike Brehm @spikebrehm HTML5DevConf April 1, 2013
  • 3.
  • 5.
  • 6. Exciting times in the world of web apps. <your framework here>
  • 8.
  • 9. +
  • 10. Poor SEO; not crawlable Performance hit to download and parse JS Duplicated application logic Context switching
  • 11. It’s still a PITA to build fast, maintainable rich-client apps.
  • 12. We started thinking... What if our JavaScript app could run on both sides?
  • 14. Provides SEO Initial pageload is drastically faster Consolidated application logic
  • 16. Meteor: client/server, but no server-side rendering; owns data layer Derby: client+server rendering, but owns data layer Mojito: client+server rendering, but full stack, and... YUI.
  • 17. Okay... how hard can it be?
  • 18.
  • 19. +
  • 20. +
  • 23. What it is. JavaScript MVC on client & server Backbone & Handlebars BaseView, BaseModel, BaseCollection, BaseApp, ClientRouter, ServerRouter... Express middleware Minimal glue between client & server
  • 25. What it ain’t. Batteries-included web framework Finished
  • 26. Design goals: • Write application logic agnostic to environment. • Library, not a framework. • Minimize if (server) {...} else {...}. • Hide complexity in library. • Talk to RESTful API. • No server-side DOM. • Simple Express middleware.
  • 27. Classes: - BaseApp < Backbone.Model - BaseModel < Backbone.Model - BaseCollection < Backbone.Collection - BaseView < Backbone.View - AppView < BaseView - ClientRouter < BaseRouter - ServerRouter < BaseRouter - ModelStore < MemoryStore - CollectionStore < MemoryStore - Fetcher
  • 28. Rendr directory structure |- client/ |- shared/ } Sent to client |- server/
  • 29. App directory structure |- app/ |- public/ |- server/
  • 30. App directory structure } |- app/ |--- collections/ |--- controllers/ |--- models/ Entire app dir |--- templates/ gets sent to |--- views/ |--- app.js client |--- router.js |--- routes.js |- public/ |- server/
  • 31. CommonJS using Stitch On the server: var User = require(‘app/models/user’); var BaseView = require(‘rendr/shared/base/view’); On the client: var User = require(‘app/models/user’); var BaseView = require(‘rendr/shared/base/view’);
  • 32. app/routes.js module.exports = function(match) { match('', 'home#index'); match('users', 'users#index'); match('users/:id', 'users#show'); };
  • 33. app/routes.js module.exports = function(match) { match('', 'home#index'); match('users', 'users#index'); match('users/:id', 'users#show'); }; controller
  • 34. app/routes.js module.exports = function(match) { match('', 'home#index'); match('users', 'users#index'); match('users/:id', 'users#show'); }; action
  • 36. On server startup, parse routes file and mount as Express routes • GET /users/1337 • Router matches "/users/:id" to "users#show" with params = {"id": 1337} • Router finds controller: require("app/controllers/users_controller") • Router executes show action with params = {"id": 1337} • The show action says to fetch User#1337 and use UsersShowView view class • Router instantiates new UsersShowView with data • Router calls view.getHtml() • Hands HTML to Express, which decorates with layout and serves response
  • 38. On page load, Router parses routes file and mounts Backbone routes • pushState /users/1337 • Router matches "/users/:id" to "users#show" with params = {"id": 1337} • Router finds controller: require("app/controllers/users_controller") • Router executes show action with params = {"id": 1337} • The show action says to fetch User#1337 and use UsersShowView view class • Router instantiates new UsersShowView with data • Router calls view.render() • Insert into DOM
  • 39. On page load, Router parses routes file and mounts Backbone routes • pushState /users/1337 • Router matches "/users/:id" to "users#show" with params = {"id": 1337} • Router finds controller: require("app/controllers/users_controller") • Router executes show action with params = {"id": 1337} • The show action says to fetch User#1337 and use UsersShowView view class • Router instantiates new UsersShowView with data • Router calls view.render() • Insert into DOM
  • 40. On page load, Router parses routes file and mounts Backbone routes • pushState /users/1337 • Router matches "/users/:id" to "users#show" with params = {"id": 1337} • Router finds controller: require("app/controllers/users_controller") • Router executes show action with params = {"id": 1337} • The show action says to fetch User#1337 and use UsersShowView view class • Router instantiates new UsersShowView with data • Router calls view.render() • Insert into DOM
  • 41. app/controllers/users_controller.js module.exports = { show: function(params, callback) { callback(null, 'users_show_view'); } };
  • 42. app/controllers/users_controller.js module.exports = { show: function(params, callback) { callback(null, 'users_show_view'); } };
  • 43. app/controllers/users_controller.js module.exports = { show: function(params, callback) { callback(null, 'users_show_view'); } };
  • 44. app/controllers/users_controller.js module.exports = { show: function(params, callback) { callback(null, 'users_show_view'); } };
  • 45. app/controllers/users_controller.js module.exports = { show: function(params, callback) { callback(null, 'users_show_view'); } }; Most simple case: no fetching of data.
  • 46. app/controllers/users_controller.js module.exports = { show: function(params, callback) { callback(null, 'users_show_view'); } }; But we want to fetch the user.
  • 47. app/controllers/users_controller.js module.exports = { show: function(params, callback) { var spec = { model: {model: ‘User’, params: params} }; this.app.fetch(spec, function(err, results) { callback(err, 'users_show_view', results); }); } };
  • 48. app/controllers/users_controller.js module.exports = { show: function(params, callback) { var spec = { model: {model: ‘User’, params: params} }; this.app.fetch(spec, function(err, results) { callback(err, 'users_show_view', results); }); } };
  • 49. app/controllers/users_controller.js module.exports = { show: function(params, callback) { var spec = { model: {model: ‘User’, params: params} }; this.app.fetch(spec, function(err, results) { callback(err, 'users_show_view', results); }); } };
  • 50. app/controllers/users_controller.js module.exports = { show: function(params, callback) { var spec = { model: {model: ‘User’, params: params} }; this.app.fetch(spec, function(err, results) { callback(err, 'users_show_view', results); }); } };
  • 51. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view' }); module.exports.id = 'users_show_view';
  • 52. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view' }); module.exports.id = 'users_show_view';
  • 53. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view' }); module.exports.id = 'users_show_view';
  • 54. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view' }); module.exports.id = 'users_show_view';
  • 55. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view', events: { 'click p': 'handleClick' }, handleClick: function() {...} }); module.exports.id = 'users_show_view';
  • 57. Rendered HTML <div class="users_show_view" data-view="users_show_view" data-model_name="user" data-model_id="1337"> <h1>User: Spike</h1> <p>From San Francisco.</p> </div>
  • 58. Rendered HTML <div class="users_show_view" data-view="users_show_view" data-model_name="user" data-model_id="1337"> <h1>User: Spike</h1> <p>From San Francisco.</p> </div>
  • 59. Rendered HTML <div class="users_show_view" data-view="users_show_view" data-model_name="user" data-model_id="1337"> <h1>User: Spike</h1> <p>From San Francisco.</p> </div>
  • 60. Rendered HTML <div class="users_show_view" data-view="users_show_view" data-model_name="user" data-model_id="1337"> <h1>User: Spike</h1> <p>From San Francisco.</p> </div>
  • 61. Where’d the data come from? Where’s the render method? How do I customize what gets passed to the template? Sensible defaults.
  • 62. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view', getTemplateData: function() { } });
  • 63. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view', getTemplateData: function() { var data = BaseView.prototype.getTemplateData .call(this); } });
  • 64. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view', getTemplateData: function() { var data = BaseView.prototype.getTemplateData .call(this); // `data` is equivalent to this.model.toJSON() } });
  • 65. app/views/users_show_view.js var BaseView = require('rendr/shared/base/view'); module.exports = BaseView.extend({ className: 'users_show_view', getTemplateData: function() { var data = BaseView.prototype.getTemplateData .call(this); // `data` is equivalent to this.model.toJSON() return _.extend(data, { nameUppercase: data.name.toUpperCase() }); } });
  • 67. Rendered HTML <div class="users_show_view" data-...> <h1>User: SPIKE</h1> <p>From San Francisco.</p> </div>
  • 68. Rendered HTML with layout <!doctype html> <html lang="en"> <head>...</head> <body> <div id="content"> <div class="users_show_view" data-view="users_show_view" data-model_name="user" data-model_id="1337"> <h1>User: SPIKE</h1> <p>From San Francisco.</p> </div> </div> <script> (function() { var App = window.App = new (require('app/app')); App.bootstrapData({ "model":{"summary":{"model":"user","id":1337}, "data":{"name":"Spike","city":"San Francisco", ...} }); App.start(); })(); </script> </body></html>
  • 69. Rendered HTML with layout <!doctype html> <html lang="en"> <head>...</head> <body> <div id="content"> <div class="users_show_view" data-view="users_show_view" data-model_name="user" data-model_id="1337"> <h1>User: SPIKE</h1> <p>From San Francisco.</p> </div> </div> <script> (function() { var App = window.App = new (require('app/app')); App.bootstrapData({ "model":{"summary":{"model":"user","id":"wycats"}, "data":{"name":"Spike","city":"San Francisco", ...} }); App.start(); })(); </script> </body></html>
  • 71. 1. Find DOM els with data-view attribute. var viewEls = $("[data-view]");
  • 72. 2. Determine model or collection based on data-model_name, data-model_id, etc. var modelName = viewEl.data(‘model_name’), modelId = viewEl.data(‘model_id’); console.log(modelName, modelId); => “user” 1337
  • 73. 3. Fetch model/collection data from ModelStore/CollectionStore. var model = modelStore.get(modelName, modelId);
  • 74. 4. Find view class. var viewName, ViewClass; viewName = viewEl.data(‘view’); ViewClass = require('app/views/' + viewName);
  • 75. 5. Instantiate view instance with model. var view = new ViewClass({ model: model, ... });
  • 76. 6. Attach to DOM el. view.setElement(viewEl);
  • 78. 8. Profit! alert(“That wasn’t so hard, right?”)
  • 79. Rendr is available starting today. github.com/airbnb/rendr
  • 80. TODO • Share routing logic between client & server. • Lazy load views, templates, etc as needed. • Support other templating languages. • Break down into smaller modules. • Rewrite in vanilla JavaScript. • much more...