A web framework for
single page apps
Created by
Owen Barnes
@temporalwave
!
!

(my boss at a former company)
About me
Paul Jensen
@paulbjensen
!
!

(I’m the new lead developer)
Where to begin?
Why Single Page
Apps?
With a traditional web app,
the user has to refresh the
page to see new information
Client

Server

Time
GET/football/live

Client

Server

Time

HTTP/1.1
HTTP/1.1 200 OK

Client

Server

Time
20 seconds later…

Client

Server

Time
I wonder what the latest score is…
Let’s reload the page

Client

Server

Time
GET/football/live

Client

Server

Time

HTTP/1.1
HTTP/1.1 304 Not Modified

Client

Server

Time
Client

Server

Time
The user had to press F5
to get at any new information
Client

Server

Time
Client

Server

Time

Even though there was
no new information,
the server still had to serve
the HTTP request
This is not a fun experience
How do we make this
better?
Client

Server

Time
We could use AJAX to
update the page
We’d save the user
having to press the F5 key
What else can we do?
Client

Server

Time
Optimise the response
GZIP the response
data, and …
Avoid sending data we
already have on the client
We could also
separate the HTML
from the data
Reuse the HTML on
the client
…and use the server to
provide you with just
data
And the web site becomes a
client

Web App

Native App

Server

API User
The server is just an API
A beautiful separation
of concerns
Overview
•

The server becomes a REST API serving JSON

•

HTML compilation is done on the client

•

As a result, less processing & bandwidth is
consumed by the server
Why Realtime?
Client

Server

Time
Polling the server every
[n] seconds for new
data is redundant
There has to be a
better way
What if the server could
send its client(s) new
data as soon as it came
about?
We can, thanks to
WebSockets
WebSockets allows data
to be sent both ways
Client

Server

Time
Client

Server

Time

Goal
The server sends a message
to the client that an action has
occurred

Client

Server

Time

Goal
We eliminate the need
to poll the server for
new data
Overview
•

We can replace AJAX polling with WebSockets,
and provide a better user experience as a result

•

We also remove the need to make redundant
polling requests back to the server.

•

We use WebSockets for sending/receiving JSON
Single Page Apps
+
The Realtime Web
There are many ways
to build this kind of
app
You could build it
mostly from scratch, and
use Express + Socket.io
Or alternatively, you
could use a web
framework like Meteor
or Firebase
SocketStream is
somewhere in-between
these 2 approaches
It provides tools to help
with building realtime
single page apps...
... Whilst trying not to
restrict what
technologies you can
use with your app
For example, we don't
provide an ORM.
Instead, you choose the
database & the ORM
Also, we don't mandate using a
specific client-side framework
!

You can use BackBone, Angular,
Ember, or something else, that is
entirely your choice.
What we focus on
instead are these
things:
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
I'll run through each of
these, 1-by-1. But first,
let's look at how to use
SocketStream
Getting started

npm install -g socketstream
!

socketstream new my_app
Getting started
!

!
!
!

Success! Created app 'my_app' with:
✓ Basic chat demo (-m for minimal install)
✓ Javascript example code (-c if you prefer CoffeeScript)
✓ Plain HTML for views (-j if you prefer Jade)
Next, run the following commands:
cd my_app
[sudo] npm install
To start your app:
node app.js

Here's what the initial file/
folder structure looks like
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
Client code is organised
into 5 sub-folders
Client side code organisation
•

CODE stores client side JavaScript files and libraries

•

CSS stores CSS files

•

STATIC stores public files like images, font files, and other
assets

•

TEMPLATES stores HTML templates for the single page
app to render on the client

•

VIEWS stores HTML files that are rendered from the server
for the initial page
Those sub-folders have subfolders, but are optional
This is how we load them
// My SocketStream 0.3 app

!

var http = require('http'),
ss = require('socketstream');

!

// Define a single-page client called 'main'
ss.client.define('main', {
view: 'app.html',
css: ['libs/reset.css', 'app.styl'],
code: ['libs/jquery.min.js', 'app'],
tmpl: '*'
});

!

// Serve this client on the root URL
ss.http.route('/', function(req, res){
res.serveClient('main');
});
// My SocketStream 0.3 app

!

var http = require('http'),
ss = require('socketstream');

!

// Define a single-page client called 'main'
ss.client.define('main', {
view: 'app.html',
css: ['libs/reset.css', 'app.styl'],
code: ['libs/jquery.min.js', 'app'],
tmpl: '*'
});

!

// Serve this client on the root URL
ss.http.route('/', function(req, res){
res.serveClient('main');
});
// My SocketStream 0.3 app

!

var http = require('http'),
ss = require('socketstream');

!

// Define a single-page client called 'main'
ss.client.define('main', {
view: 'app.html',
css: ['libs/reset.css', 'app.styl'],
code: ['libs/jquery.min.js', 'app'],
tmpl: '*'
});

!

// Serve this client on the root URL
ss.http.route('/', function(req, res){
res.serveClient('main');
});
// My SocketStream 0.3 app

!

var http = require('http'),
ss = require('socketstream');

!

// Define a single-page client called 'main'
ss.client.define('main', {
view: 'app.html',
css: ['libs/reset.css', 'app.styl'],
code: ['libs/jquery.min.js', 'app'],
tmpl: '*'
});

!

// Serve this client on the root URL
ss.http.route('/', function(req, res){
res.serveClient('main');
});
// My SocketStream 0.3 app

!

var http = require('http'),
ss = require('socketstream');

!

// Define a single-page client called 'main'
ss.client.define('main', {
view: 'app.html',
css: ['libs/reset.css', 'app.styl'],
code: ['libs/jquery.min.js', 'app'],
tmpl: '*'
});

!

// Serve this client on the root URL
ss.http.route('/', function(req, res){
res.serveClient('main');
});
// My SocketStream 0.3 app

!

var http = require('http'),
ss = require('socketstream');

!

// Define a single-page client called 'main'
ss.client.define('main', {
view: 'app.html',
css: ['libs/reset.css', 'app.styl'],
code: ['libs/jquery.min.js', 'app'],
tmpl: '*'
});

!

// Serve this client on the root URL
ss.http.route('/', function(req, res){
res.serveClient('main');
});
// My SocketStream 0.3 app

!

var http = require('http'),
ss = require('socketstream');

!

// Define a single-page client called 'main'
ss.client.define('main', {
view: 'app.html',
css: ['libs/reset.css', 'app.styl'],
code: ['libs/jquery.min.js', 'app'],
tmpl: '*'
});

!

// Serve this client on the root URL
ss.http.route('/', function(req, res){
res.serveClient('main');
});
SocketStream uses
Browserify to handle
requiring JS files
Browserify allows us to
use a Node.js style of
requiring JS files
// This file automatically gets called first by
SocketStream and must always exist

!

// Make 'ss' available to all modules and the
browser console
window.ss = require('socketstream');

!

ss.server.on('disconnect', function(){
console.log('Connection down :-(');
});

!

ss.server.on('reconnect', function(){
console.log('Connection back up :-)');
});

!

ss.server.on('ready', function(){

!

!
!

// Wait for the DOM to finish loading
jQuery(function(){
// Load app
require('/app');
});

});
// This file automatically gets called first by
SocketStream and must always exist

!

// Make 'ss' available to all modules and the
browser console
window.ss = require('socketstream');

!

ss.server.on('disconnect', function(){
console.log('Connection down :-(');
});

!

ss.server.on('reconnect', function(){
console.log('Connection back up :-)');
});

!

ss.server.on('ready', function(){

!

!
!

// Wait for the DOM to finish loading
jQuery(function(){
// Load app
require('/app');
});

});
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
Over the years, developers
have come up with new
languages to generate
HTML, CSS, and JavaScript
SocketStream allows
developers to use these
code preprocessors in
their apps
Adding a preprocessor is simple

// Code Formatters
ss.client.formatters.add(require('ss-stylus'));
For Javascript

•

SS-COFFEE - supports using CoffeeScript

•

SS-GORILLA - supports using GorillaScript
For CSS

•

SS-STYLUS - supports using Stylus

•

SS-LESS - supports using Less
For HTML Views

•

SS-JADE - supports using Jade
For HTML Templating

•

SS-HOGAN - supports using Twitter's Hogan.js

•

SS-COFFEEKUP - supports using CoffeeKup
Setting a Templating engine

// Use server-side compiled Hogan (Mustache)
templates. Others engines available
ss.client.templateEngine.use(require('ss-hogan'));
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
Having to press F5 to reload
the page in order to view
changes to HTML/CSS/JS...
... is not a fun experience
In development mode,
SocketStream will watch the
client files for changes, and
reload the page when they
occur
In the case of CSS,
SocketStream will apply
the changes without
reloading the page
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
Client-side HTML
templates are made
available to the browser
via the ss.tmpl object
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
When you're building a
single page app, you'll
have a lot of JS files, and
maybe a few CSS files
But serving a HTML
page with lots of these
files can take time, and
is inefficient
SocketStream provides a
way to concatenate, minify,
and GZip these files into 1
JS and 1 CSS file
This saves bytes being
transferred, as well as
reducing the number of
HTTP requests you make
Also, you can tell
SocketStream to load
these files from a CDN
Setting a Templating engine

// Minimize and pack assets if you type: SS_ENV=production node app.js
if (ss.env === 'production') ss.client.packAssets();
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
Web Workers are handy
for intensive client-side
JS operations
SocketStream provides
support for using Web
Workers in your app
First, create a folder
Next, put your web worker files in
that folder
Then, load the worker in a client
code file, and enjoy
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
SocketStream uses
Connect middleware to
support HTTP features
SocketStream uses the following
middleware by default:
•

compress - for GZipping assets

•

cookieParser - for handling user tracking

•

favicon - for serving a favicon.ico file

•

session - for handling sessions

•

static - for serving static assets
SocketStream uses the following
middleware by default:
•

compress middleware is loaded first, before all
other middleware

•

static middleware is loaded last, after all other
middleware
SocketStream provides
a way to load custom
middleware into the
connect stack
ss.http.middleware.prepend()
ss.http.middleware.append()
This allows you to use all
of the connect
middleware out there
today, i.e. EveryAuth
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
We use connect’s session
middleware, so authentication
can be done with either
EveryAuth, PassportJS, or you
can roll your own.
We also recommend
using connect-redis
Both HTTP and
WebSocket interfaces
can get/set the session
data
Via HTTP
// app.js
ss.http.router.on('/updateSession', function(req, res) {
req.session.myVar = 4321;
res.end('req.session.myVar has been updated to', req.session.myVar);
});
Via WebSockets
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
RPC is a common
pattern for clients
requesting data from
the server
SocketStream provides
a way to construct RPC
APIs with flexibility
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
PubSub is a great
pattern for Single Page
Apps
SocketStream handles
this in various ways:
1 - Publishing to everyone
viewing the app right now
Server
ss.publish.all('newMessage', message);

// Broadcast the message to everyone

Client
// Listen out for newMessage events coming from the server
ss.event.on('newMessage', function(message) {
// do something with the message
});
2 - Sending to private channels
Server (subscribe/unsubscribe the session )
// in a /server/rpc file after calling req.use('session') middleware

!

req.session.channel.subscribe('disney')

!

req.session.channel.unsubscribe('kids')

!

req.session.channel.reset()

// unsubscribes the session from every channel

req.session.channel.list()

// shows what channels are subscribed to

!
2 - Sending to private channels
Server (publish to channel)
// in a /server/rpc file
ss.publish.channel('disney', 'chatMessage', {from: 'jerry', message: 'Has anyone seen
Tom?'});

Client (receive channel message)
// in a /client/code file
ss.event.on('chatMessage', function(msg, channelName){
console.log('The following message was sent to the ' + channelName + ' channel:', msg);
});
3 - Sending to users
Server
// in a /server/rpc file
ss.publish.user('fred', 'specialOffer', 'Here is a special offer just for you!');
4 - Sending to a browser
tab
Server
// in a /server/rpc file
ss.publish.socketId('254987654324567', 'justForMe', 'Just for one tab');
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
On top of RPC and PubSub,
SocketStream provides you
with a way to create custom
request responders
Request Response is
basically a WebSocket
message handler
It allows you to write
message handling for
games, where every
byte matters
HTML / CSS / JS
code preprocessing

Minifying CSS/JS for
production use

Client-side code
organisation

HTML Templates

WebSocket
Management

Live Reload

Building RPC APIs

Building PubSub APIs

Session Management

Building custom APIs
on top of WS

Web Workers

Connect middleware
compatibility
WebSockets are not
immortal…
They are mangled by
mobile networks…
Blocked by firewalls…
Routed to dead ends by
proxy servers
And severed by train
tunnels
Also, browser support
for WebSockets isn’t
guaranteed
You need a transport
strategy
Originally, SocketStream
used Socket.io
But Socket.io asserted
that if a browser
supported WebSockets,
then it would work
They learned from this,
by building Engine.io
I created the transport
wrapper for Engine.io in
SocketStream for
Bechtel & Dashku
And designed it to
reconnect the client
when severed
Months later, it made it’s
way into SocketStream’s
core.
SocketStream let’s you
use this, alongside
SockJS
…and that is
SocketStream in a
nutshell. Whew!
Let’s look at some
SocketStream apps in
the wild
Hollow
hollowdocumentary.com
Vmux
vmux.co
Dashku
dashku.com
SocketStream plugins
SS-BACKBONE
SS-ANGULAR
SS-CUCUMBER
Tips for deploying
SocketStream in
production
1 - Check your server’s
ulimit configuration
(This can bite you hard)
I learned this when Dashku went
#1 on Hacker News in 45min
2 - Use HTTPS, but
handle it at the load
balancer level rather
than at the app level
HTTPS helps to improve
the stability of WebSocket
connections, especially
on mobile devices
But Node’s HTTPS
implementation is
noticeably slower than
using HAProxy or Nginx
Where is SocketStream
going next?
We’re in the process of
getting SocketStream’s
test coverage up
We’re also trying to
close some ancient
bugs
We also need better
documentation
We’re giving the web
site an overhaul
And we want to
document how
SocketStream’s internals
function, to help build 0.4
but what about 0.4?
…0.4 is starting to look like these:
I promise you all, it’s
coming in June 2014
Thank You

SocketStream

  • 2.
    A web frameworkfor single page apps
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
    With a traditionalweb app, the user has to refresh the page to see new information
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
    I wonder whatthe latest score is… Let’s reload the page Client Server Time
  • 13.
  • 14.
    HTTP/1.1 304 NotModified Client Server Time
  • 15.
  • 16.
    The user hadto press F5 to get at any new information Client Server Time
  • 17.
    Client Server Time Even though therewas no new information, the server still had to serve the HTTP request
  • 18.
    This is nota fun experience
  • 19.
    How do wemake this better?
  • 20.
  • 21.
    We could useAJAX to update the page
  • 22.
    We’d save theuser having to press the F5 key
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
    Avoid sending datawe already have on the client
  • 28.
    We could also separatethe HTML from the data
  • 29.
    Reuse the HTMLon the client
  • 30.
    …and use theserver to provide you with just data
  • 31.
    And the website becomes a client Web App Native App Server API User
  • 32.
    The server isjust an API
  • 33.
  • 34.
    Overview • The server becomesa REST API serving JSON • HTML compilation is done on the client • As a result, less processing & bandwidth is consumed by the server
  • 35.
  • 36.
  • 37.
    Polling the serverevery [n] seconds for new data is redundant
  • 38.
    There has tobe a better way
  • 39.
    What if theserver could send its client(s) new data as soon as it came about?
  • 40.
    We can, thanksto WebSockets
  • 41.
    WebSockets allows data tobe sent both ways
  • 42.
  • 43.
  • 44.
    The server sendsa message to the client that an action has occurred Client Server Time Goal
  • 45.
    We eliminate theneed to poll the server for new data
  • 46.
    Overview • We can replaceAJAX polling with WebSockets, and provide a better user experience as a result • We also remove the need to make redundant polling requests back to the server. • We use WebSockets for sending/receiving JSON
  • 47.
  • 48.
    There are manyways to build this kind of app
  • 49.
    You could buildit mostly from scratch, and use Express + Socket.io
  • 50.
    Or alternatively, you coulduse a web framework like Meteor or Firebase
  • 51.
  • 52.
    It provides toolsto help with building realtime single page apps...
  • 53.
    ... Whilst tryingnot to restrict what technologies you can use with your app
  • 54.
    For example, wedon't provide an ORM. Instead, you choose the database & the ORM
  • 55.
    Also, we don'tmandate using a specific client-side framework ! You can use BackBone, Angular, Ember, or something else, that is entirely your choice.
  • 56.
    What we focuson instead are these things:
  • 57.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 58.
    I'll run througheach of these, 1-by-1. But first, let's look at how to use SocketStream
  • 59.
    Getting started npm install-g socketstream ! socketstream new my_app
  • 60.
    Getting started ! ! ! ! Success! Createdapp 'my_app' with: ✓ Basic chat demo (-m for minimal install) ✓ Javascript example code (-c if you prefer CoffeeScript) ✓ Plain HTML for views (-j if you prefer Jade) Next, run the following commands: cd my_app [sudo] npm install To start your app: node app.js

  • 61.
    Here's what theinitial file/ folder structure looks like
  • 62.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 63.
    Client code isorganised into 5 sub-folders
  • 64.
    Client side codeorganisation • CODE stores client side JavaScript files and libraries • CSS stores CSS files • STATIC stores public files like images, font files, and other assets • TEMPLATES stores HTML templates for the single page app to render on the client • VIEWS stores HTML files that are rendered from the server for the initial page
  • 65.
    Those sub-folders havesubfolders, but are optional
  • 66.
    This is howwe load them // My SocketStream 0.3 app ! var http = require('http'), ss = require('socketstream'); ! // Define a single-page client called 'main' ss.client.define('main', { view: 'app.html', css: ['libs/reset.css', 'app.styl'], code: ['libs/jquery.min.js', 'app'], tmpl: '*' }); ! // Serve this client on the root URL ss.http.route('/', function(req, res){ res.serveClient('main'); });
  • 67.
    // My SocketStream0.3 app ! var http = require('http'), ss = require('socketstream'); ! // Define a single-page client called 'main' ss.client.define('main', { view: 'app.html', css: ['libs/reset.css', 'app.styl'], code: ['libs/jquery.min.js', 'app'], tmpl: '*' }); ! // Serve this client on the root URL ss.http.route('/', function(req, res){ res.serveClient('main'); });
  • 68.
    // My SocketStream0.3 app ! var http = require('http'), ss = require('socketstream'); ! // Define a single-page client called 'main' ss.client.define('main', { view: 'app.html', css: ['libs/reset.css', 'app.styl'], code: ['libs/jquery.min.js', 'app'], tmpl: '*' }); ! // Serve this client on the root URL ss.http.route('/', function(req, res){ res.serveClient('main'); });
  • 69.
    // My SocketStream0.3 app ! var http = require('http'), ss = require('socketstream'); ! // Define a single-page client called 'main' ss.client.define('main', { view: 'app.html', css: ['libs/reset.css', 'app.styl'], code: ['libs/jquery.min.js', 'app'], tmpl: '*' }); ! // Serve this client on the root URL ss.http.route('/', function(req, res){ res.serveClient('main'); });
  • 70.
    // My SocketStream0.3 app ! var http = require('http'), ss = require('socketstream'); ! // Define a single-page client called 'main' ss.client.define('main', { view: 'app.html', css: ['libs/reset.css', 'app.styl'], code: ['libs/jquery.min.js', 'app'], tmpl: '*' }); ! // Serve this client on the root URL ss.http.route('/', function(req, res){ res.serveClient('main'); });
  • 71.
    // My SocketStream0.3 app ! var http = require('http'), ss = require('socketstream'); ! // Define a single-page client called 'main' ss.client.define('main', { view: 'app.html', css: ['libs/reset.css', 'app.styl'], code: ['libs/jquery.min.js', 'app'], tmpl: '*' }); ! // Serve this client on the root URL ss.http.route('/', function(req, res){ res.serveClient('main'); });
  • 72.
    // My SocketStream0.3 app ! var http = require('http'), ss = require('socketstream'); ! // Define a single-page client called 'main' ss.client.define('main', { view: 'app.html', css: ['libs/reset.css', 'app.styl'], code: ['libs/jquery.min.js', 'app'], tmpl: '*' }); ! // Serve this client on the root URL ss.http.route('/', function(req, res){ res.serveClient('main'); });
  • 73.
    SocketStream uses Browserify tohandle requiring JS files
  • 74.
    Browserify allows usto use a Node.js style of requiring JS files
  • 75.
    // This fileautomatically gets called first by SocketStream and must always exist ! // Make 'ss' available to all modules and the browser console window.ss = require('socketstream'); ! ss.server.on('disconnect', function(){ console.log('Connection down :-('); }); ! ss.server.on('reconnect', function(){ console.log('Connection back up :-)'); }); ! ss.server.on('ready', function(){ ! ! ! // Wait for the DOM to finish loading jQuery(function(){ // Load app require('/app'); }); });
  • 76.
    // This fileautomatically gets called first by SocketStream and must always exist ! // Make 'ss' available to all modules and the browser console window.ss = require('socketstream'); ! ss.server.on('disconnect', function(){ console.log('Connection down :-('); }); ! ss.server.on('reconnect', function(){ console.log('Connection back up :-)'); }); ! ss.server.on('ready', function(){ ! ! ! // Wait for the DOM to finish loading jQuery(function(){ // Load app require('/app'); }); });
  • 77.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 78.
    Over the years,developers have come up with new languages to generate HTML, CSS, and JavaScript
  • 79.
    SocketStream allows developers touse these code preprocessors in their apps
  • 80.
    Adding a preprocessoris simple // Code Formatters ss.client.formatters.add(require('ss-stylus'));
  • 81.
    For Javascript • SS-COFFEE -supports using CoffeeScript • SS-GORILLA - supports using GorillaScript
  • 82.
    For CSS • SS-STYLUS -supports using Stylus • SS-LESS - supports using Less
  • 83.
    For HTML Views • SS-JADE- supports using Jade
  • 84.
    For HTML Templating • SS-HOGAN- supports using Twitter's Hogan.js • SS-COFFEEKUP - supports using CoffeeKup
  • 85.
    Setting a Templatingengine // Use server-side compiled Hogan (Mustache) templates. Others engines available ss.client.templateEngine.use(require('ss-hogan'));
  • 86.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 87.
    Having to pressF5 to reload the page in order to view changes to HTML/CSS/JS...
  • 88.
    ... is nota fun experience
  • 89.
    In development mode, SocketStreamwill watch the client files for changes, and reload the page when they occur
  • 90.
    In the caseof CSS, SocketStream will apply the changes without reloading the page
  • 91.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 92.
    Client-side HTML templates aremade available to the browser via the ss.tmpl object
  • 94.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 95.
    When you're buildinga single page app, you'll have a lot of JS files, and maybe a few CSS files
  • 96.
    But serving aHTML page with lots of these files can take time, and is inefficient
  • 97.
    SocketStream provides a wayto concatenate, minify, and GZip these files into 1 JS and 1 CSS file
  • 98.
    This saves bytesbeing transferred, as well as reducing the number of HTTP requests you make
  • 99.
    Also, you cantell SocketStream to load these files from a CDN
  • 100.
    Setting a Templatingengine // Minimize and pack assets if you type: SS_ENV=production node app.js if (ss.env === 'production') ss.client.packAssets();
  • 101.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 102.
    Web Workers arehandy for intensive client-side JS operations
  • 103.
    SocketStream provides support forusing Web Workers in your app
  • 104.
  • 105.
    Next, put yourweb worker files in that folder
  • 106.
    Then, load theworker in a client code file, and enjoy
  • 107.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 108.
    SocketStream uses Connect middlewareto support HTTP features
  • 109.
    SocketStream uses thefollowing middleware by default: • compress - for GZipping assets • cookieParser - for handling user tracking • favicon - for serving a favicon.ico file • session - for handling sessions • static - for serving static assets
  • 110.
    SocketStream uses thefollowing middleware by default: • compress middleware is loaded first, before all other middleware • static middleware is loaded last, after all other middleware
  • 111.
    SocketStream provides a wayto load custom middleware into the connect stack
  • 112.
  • 113.
    This allows youto use all of the connect middleware out there today, i.e. EveryAuth
  • 114.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 115.
    We use connect’ssession middleware, so authentication can be done with either EveryAuth, PassportJS, or you can roll your own.
  • 116.
  • 117.
    Both HTTP and WebSocketinterfaces can get/set the session data
  • 118.
    Via HTTP // app.js ss.http.router.on('/updateSession',function(req, res) { req.session.myVar = 4321; res.end('req.session.myVar has been updated to', req.session.myVar); });
  • 119.
  • 120.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 121.
    RPC is acommon pattern for clients requesting data from the server
  • 122.
    SocketStream provides a wayto construct RPC APIs with flexibility
  • 125.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 126.
    PubSub is agreat pattern for Single Page Apps
  • 127.
  • 128.
    1 - Publishingto everyone viewing the app right now Server ss.publish.all('newMessage', message); // Broadcast the message to everyone Client // Listen out for newMessage events coming from the server ss.event.on('newMessage', function(message) { // do something with the message });
  • 129.
    2 - Sendingto private channels Server (subscribe/unsubscribe the session ) // in a /server/rpc file after calling req.use('session') middleware ! req.session.channel.subscribe('disney') ! req.session.channel.unsubscribe('kids') ! req.session.channel.reset() // unsubscribes the session from every channel req.session.channel.list() // shows what channels are subscribed to !
  • 130.
    2 - Sendingto private channels Server (publish to channel) // in a /server/rpc file ss.publish.channel('disney', 'chatMessage', {from: 'jerry', message: 'Has anyone seen Tom?'}); Client (receive channel message) // in a /client/code file ss.event.on('chatMessage', function(msg, channelName){ console.log('The following message was sent to the ' + channelName + ' channel:', msg); });
  • 131.
    3 - Sendingto users Server // in a /server/rpc file ss.publish.user('fred', 'specialOffer', 'Here is a special offer just for you!');
  • 132.
    4 - Sendingto a browser tab Server // in a /server/rpc file ss.publish.socketId('254987654324567', 'justForMe', 'Just for one tab');
  • 133.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 134.
    On top ofRPC and PubSub, SocketStream provides you with a way to create custom request responders
  • 135.
    Request Response is basicallya WebSocket message handler
  • 136.
    It allows youto write message handling for games, where every byte matters
  • 137.
    HTML / CSS/ JS code preprocessing Minifying CSS/JS for production use Client-side code organisation HTML Templates WebSocket Management Live Reload Building RPC APIs Building PubSub APIs Session Management Building custom APIs on top of WS Web Workers Connect middleware compatibility
  • 138.
  • 139.
    They are mangledby mobile networks…
  • 140.
  • 141.
    Routed to deadends by proxy servers
  • 142.
    And severed bytrain tunnels
  • 143.
    Also, browser support forWebSockets isn’t guaranteed
  • 144.
    You need atransport strategy
  • 145.
  • 146.
    But Socket.io asserted thatif a browser supported WebSockets, then it would work
  • 147.
    They learned fromthis, by building Engine.io
  • 148.
    I created thetransport wrapper for Engine.io in SocketStream for Bechtel & Dashku
  • 149.
    And designed itto reconnect the client when severed
  • 150.
    Months later, itmade it’s way into SocketStream’s core.
  • 151.
    SocketStream let’s you usethis, alongside SockJS
  • 152.
    …and that is SocketStreamin a nutshell. Whew!
  • 153.
    Let’s look atsome SocketStream apps in the wild
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
    1 - Checkyour server’s ulimit configuration (This can bite you hard)
  • 163.
    I learned thiswhen Dashku went #1 on Hacker News in 45min
  • 164.
    2 - UseHTTPS, but handle it at the load balancer level rather than at the app level
  • 165.
    HTTPS helps toimprove the stability of WebSocket connections, especially on mobile devices
  • 166.
    But Node’s HTTPS implementationis noticeably slower than using HAProxy or Nginx
  • 167.
  • 168.
    We’re in theprocess of getting SocketStream’s test coverage up
  • 169.
    We’re also tryingto close some ancient bugs
  • 170.
    We also needbetter documentation
  • 171.
    We’re giving theweb site an overhaul
  • 172.
    And we wantto document how SocketStream’s internals function, to help build 0.4
  • 173.
  • 174.
    …0.4 is startingto look like these:
  • 175.
    I promise youall, it’s coming in June 2014
  • 176.