Follow

SocketStream introduction

A talk about SocketStream, given at the Cologne.js meetup in 2012

In 2012, real-time web applications were still exotic, and SocketStream was one of the frameworks arguing that WebSockets should change how we structure a web app.

I gave the introductory talk at the Cologne.js meetup on 11 September 2012, at CoWoCo in Cologne. The slides are still hosted.


FactDetail
OccasionCologne.js user meetup, 11 September 2012
VenueCoWoCo, Cologne
TopicSocketStream / real-time web apps
HostedGitHub Pages

What's in it

Speaking, early

One of the first talks — the habit of explaining what I work with started here.

Still online

The hosted version has outlived the framework's moment, which is its own kind of documentation.

In detail

What is actually inside it

Markdown slides

Long before slide frameworks shipped markdown support, a showdown loader meant the content was text you could diff.

Still online

Hosted on GitHub Pages since 2012 — a talk about real-time web apps that outlived the framework's moment.

DetailValue
Formatreveal.js + showdown (markdown) + highlight.js
OccasionCologne.js meetup, 11 September 2012
HostedGitHub Pages

Technical notes

The decisions behind it

Why SocketStream, in 2012?
Because it argued that WebSockets should change how you structure an application, not just how you push updates. That argument aged better than any particular framework.

The argument, slide by slide

What the talk actually claimed

Under the headings, the deck is a definition that turns into a design. SocketStream is "a modular Node.js web framework for building fast, responsive single-page realtime apps" — not a realtime add-on bolted onto an HTTP app, but a framework whose transport is the application. The talk walks that through in 8 top-level sections (24 slides in total).

Concretely, a 2012 app would open one socket — Socket.IO in 0.3, SockJS as a modular alternative — and hang the app off it. ss.rpc('board.current', callback) calls a server action by name and answers asynchronously; ss.publish.all('newUser', user) pushes to every connected client; req.session.channel.subscribe('boardUpdates') scopes those pushes to a channel. The route handler never renders HTML — res.serveClient('main') ships a named client, which ss.client.define('main', …) composed from a view, CSS, libs/jquery.min.js, app code and templates.

The unusual bet is the module system. window.ss = require('socketstream') and exports.actions run the same CommonJS require/exports idiom on client and server, years before Browserify or Webpack made that ordinary, so the two sides can share code. Sessions cross the wire too: once an RPC action adds req.use('session'), the same req.session — including session.facebook set during the initial HTTP handshake — is visible inside socket calls.

Nothing in the examples is hypothetical: every snippet is captioned "code examples based on our app". That app is a board: clients call board.current, subscribe to boardUpdates, upload through fileupload.html and userdetails.html, authenticate via a facebookAuth.js middleware, and download a zipped set of images per version through a custom zipStream.js — the screen shown on the Demo slide, where the terminal reads SockJS v0.3.1 bound to "/ws" and a Console Server running on port 5000.


What did the SocketStream 0.4 roadmap promise?
The last content slide is a list of what 0.3 taught the authors: a new Stream API to pipe() news feeds and the like over the socket, an improved Request Responder API, Engine.IO bundled by default and explicitly replacing Socket.IO, optional Gzip of assets, a server-side event bus, and a complete switch from CoffeeScript to JavaScript. The version quoted on the SocketStream slide is still 0.31 — the talk sits right before that rewrite.
Which production gotchas did the talk name?
Three, all rooted in "one socket per user": raise ulimit on the server so it can hold many concurrent connections; send a P3P header on the first response or Internet Explorer refuses the session cookies the socket then depends on; and accept that Heroku did not support WebSockets at all. The last one is the honest one — in 2012, shipping a realtime app was not yet a commodity.
How was shared server state exposed?
Because every visitor has a live socket, the process is long-lived. ss.api.add('db', client) puts a database connection on a process-global ss namespace, and ss.api.add('environment', env) does the same for config; every RPC action then reaches them as ss.db / ss.environment. It is a global, and a direct consequence of the framework owning the whole process instead of plugging into an Express app.

How this deck is built

The machinery under the slides

The repository was not started from scratch. It was cloned from reveal.js at commit 28567f32 — the parent of the first project commit is one of Hakim El Hattab's merge commits from 10 September 2012 — then retargeted: the initial commit replaces the template's index.html (+596/-321 lines) and tweaks css/main.css (+24/-1), keeping the whole upstream history in the log. Two template leftovers survive: package.json still declares reveal.js@1.5.0 while the vendored js/reveal.js announces reveal.js 2.0 r23, and <meta name="author"> still credits Hakim El Hattab.

The markdown path is inherited rather than used: showdown.js and data-markdown.js are registered as conditional dependencies, loaded only if document.querySelector('[data-markdown]') matches — and no slide carries that attribute. Every slide is hand-written <section> markup. What the deck does lean on is reveal.js's other 2012 features: 80 class="fragment" steps, history: true for deep-linked slide URLs, a progress bar, and contenteditable code blocks (25 of them) so a <pre> could be selected and copied.

DetailValue
Slide enginereveal.js 2.0 r23, vendored in `js/reveal.js`
package.jsonstill says `1.5.0` — stale from upstream
Markdownshowdown + data-markdown, loaded only when `[data-markdown]` exists (no slide uses it)
Highlightinghighlight.js with `lib/css/zenburn.css`
Print`paper.css`, swapped for `pdf.css` by a `?print-pdf` query parameter
Presenter notes`plugin/speakernotes` — Express + socket.io on port 1947, loaded only when the host is `localhost:1947`
Hosting`gh-pages` branch, deployed 12 September 2012
Repo originfork of `hakimel/reveal.js`, upstream history retained

What happened next

The 2012 bets, scored

The talk ends on a roadmap and a demo, and the exit is where the accounting gets interesting. SocketStream did ship the rewrite it promised — it just took a while.
3515
GitHub stars
socketstream/socketstream today — a real audience, not a toy.
2015
0.4.0 lands
The promised rewrite shipped in April 2015, two and a half years after the talk; 0.5.3 in December 2015 was the final release.
2019
Unmaintained
The maintainers' notice: "SocketStream isn't maintained anymore … please consider [other frameworks] instead."
The technical prediction aged better than the project. The slide said 0.4 would replace Socket.IO with Engine.IO — and Engine.IO is now described by its own maintainers as "the engine used in the Socket.IO JavaScript server", the low-level transport layer the library was rebuilt on. The larger bet did not win: that one long-lived socket would be the spine of the app, with RPC and server-pushed events replacing request/response. The web kept HTTP as its default and grew realtime at the edges. SocketStream's single-socket, convention-over-configuration framework became a road not taken — worth reading precisely because it pushed the idea further than the mainstream ever did.