Alan Peabody - Developer @ Agilion
//= jquery
//= underscore
//= backbone
//= require my_app_setup
//= require_tree models/
//= require_tree collections/
//= require_tree templates/
//= require_tree views/
//= require_tree routers/
//= require my_app_start
//my_app_setup.js
window.App = {};
App.Models = {};
App.Collections = {};
App.Controllers = {};
App.Routes = {};
App.Views = {};
The request response cycle is terrible for maintaining application state,
and the asset pipeline is terrible for building JavaScript Single Page Apps.
Treating the UI as its own application
AppAPI/
.git
Gemfile
Rakefile
app/
AppUI/
.git
package.json
bower.json
gulpfile.js
app/
Development/build tools dependencies
Like development group Gemfile dependencies
//package.json
{
"name": "MyAppUI",
"description": "UI for MyApp",
"version": "0.0.1",
"private": true,
"dependencies": {
"gulp": "~3.8.6",
"gulp-concat": "~2.3.4",
"browserify": "~5.9.1",
"less": "~1.7.4",
"bower": "~1.3.8",
"browser-sync": "~1.3.2"
}
}
npm install
// bower.json
{
"name": "MyAppUI",
"version": "0.0.1",
"private": true,
"dependencies": {
"jquery": "~2.0.3",
"bootstrap": "~3.0.3",
"backbone": "~1.1.2"
}
}
bower install
Gem based bower wrapper: Rails Assets
// app/collections/users.js
var Backbone = require('backbone'),
User = require('./app/models/user');
module.export = Backbone.Collection.extend({
model: User
});
Alternatives: require.js, ES6 Module Transpiler
var gulp = require('gulp'),
browserify = require('browserify'),
gconcat = require('gulp-concat');
gulp.task('javascript', function() {
gulp.src('application.js')
.pipe(browserify({debug: !gulp.env.production}))
.pipe(gconcat('build.js'))
.pipe(gulp.dest('./dist/'));
});
gulp.task('default', function() {
gulp.watch('js/**', ['js']);
});
gulp javascript
gulp
var gulp = require('gulp'),
browserify = require('browserify'),
gconcat = require('gulp-concat'),
browserSync = require('browser-sync');
gulp.task('javascript', function() {
gulp.src('application.js')
.pipe(browserify({debug: !gulp.env.production}))
.pipe(gconcat('build.js'))
.pipe(gulp.dest('./dist/'))
.pipe(browserSync.reload({stream: true, once: true});
});
gulp.task('browser-sync', function() {
browserSync({server: { baseDir: "./", port: 4200 }});
});
gulp.task('default', ['browser-sync'], function() {
gulp.watch('js/**', ['js']);
});
Alternatives: Live Reload
2 Heroku Apps w/ Cross Origin Resource Sharing (CORS)
Your front end application deserves to be treated as an application in its own right,
not relegated to the asset directory.
Finally a real RESTful API!
// POST /api/token
{
grant_type: "password",
username: "alan@agilion.com",
password: "correct horse battery staple"
}
// response 200
{
access_token: 'sdlkyuskdfyiwesdfkljsdf',
token_type: 'Bearer',
expires_in: 30.days,
user_id: 1
}
GET /api/protected
Headers: 'Authorization': "Bearer #{access_token}"
class UsersController < ApplicationController
def show
render json: User.find(params[:id]), serializer: UserSerializer
end
end
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :email, :is_admin
def is_admin
object.admin?
end
end
{
"user": {
{
"id" : 1,
"name" : "alan",
"email" : "alan@agilion.com",
"is_admin": true
}
}
}
On Github
2 Heroku apps with Nginx Proxy
Oh yeah I would never go back by choice.
- Pete Brown
*Or at least it feels faster
We have the opportunity to build a synergistic, mobile enabled, web platform at an accelerated pace with a dynamic user experience years ahead of its time.
Twitter: @alanpeabody
http://slides.com/alanpeabody/breaking-up-with-the-asset-pipeline-2/