Permalink
Browse files

streaming html example section

  • Loading branch information...
1 parent 02c101c commit a974c639e0095d53ab4d449a6b19175c7711e15d @substack committed May 23, 2013
Showing with 144 additions and 0 deletions.
  1. +144 −0 readme.markdown
View
@@ -780,6 +780,11 @@ incrementally as it arrives.
***
+# html streams
+
+## [hyperstream](https://github.com/substack/hypersream)
+
+
# audio streams
## [baudio](https://github.com/substack/baudio)
@@ -1058,3 +1063,142 @@ create separate channels for each different kind of stream that you need.
As the requirements of your system evolve over time, you can swap out each of
these streaming pieces as necessary without as many of the all-or-nothing risks
that more opinionated framework approaches necessarily entail.
+
+## html streams for the browser and the server
+
+We can use some streaming modules to reuse the same html rendering logic for the
+client and the server! This approach is indexable, SEO-friendly, and gives us
+realtime updates.
+
+Our renderer takes lines of json as input and returns html strings as its
+output. Text, the universal interface!
+
+render.js:
+
+``` js
+var through = require('through');
+var hyperglue = require('hyperglue');
+var fs = require('fs');
+var html = fs.readFileSync(__dirname + '/static/row.html');
+
+module.exports = function () {
+ return through(function (line) {
+ try { var row = JSON.parse(line) }
+ catch (err) { return this.emit('error', err) }
+
+ this.queue(hyperglue(html, {
+ '.who': row.who,
+ '.message': row.message
+ }).outerHTML);
+ });
+};
+```
+
+We can use [brfs](http://github.com/substack/brfs) to inline the
+`fs.readFileSync()` call for browser code
+and [hyperglue](https://github.com/substack/hyperglue) to update html based on
+css selectors. You don't need to use hyperglue necessarily here; anything that
+can return a string with html in it will work.
+
+The `row.html` used is just a really simple stub thing:
+
+row.html:
+
+``` html
+<div class="row">
+ <div class="who"></div>
+ <div class="message"></div>
+</div>
+```
+
+The server will just use [slice-file](https://github.com/substack/slice-file) to
+keep everything simple. [slice-file](https://github.com/substack/slice-file) is
+little more than a glorified `tail/tail -f` api but the interfaces map well to
+databases with regular results plus a changes feed like couchdb.
+
+server.js:
+
+``` js
+var http = require('http');
+var fs = require('fs');
+var hyperstream = require('hyperstream');
+var ecstatic = require('ecstatic')(__dirname + '/static');
+
+var sliceFile = require('slice-file');
+var sf = sliceFile(__dirname + '/data.txt');
+
+var render = require('./render');
+
+var server = http.createServer(function (req, res) {
+ if (req.url === '/') {
+ var hs = hyperstream({
+ '#rows': sf.slice(-5).pipe(render())
+ });
+ hs.pipe(res);
+ fs.createReadStream(__dirname + '/static/index.html').pipe(hs);
+ }
+ else ecstatic(req, res)
+});
+server.listen(8000);
+
+var shoe = require('shoe');
+var sock = shoe(function (stream) {
+ sf.follow(-1,0).pipe(stream);
+});
+sock.install(server, '/sock');
+```
+
+The first part of the server handles the `/` route and streams the last 5 lines
+from `data.txt` into the `#rows` div.
+
+The second part of the server handles realtime updates to `#rows` using
+[shoe](http://github.com/substack/shoe), a simple streaming websocket polyfill.
+
+Next we can write some simple browser code to populate the realtime updates
+from [shoe](http://github.com/substack/shoe) into the `#rows` div:
+
+``` js
+var through = require('through');
+var render = require('./render');
+
+var shoe = require('shoe');
+var stream = shoe('/sock');
+
+var rows = document.querySelector('#rows');
+stream.pipe(render()).pipe(through(function (html) {
+ rows.innerHTML += html;
+}));
+```
+
+Just compile with [browserify](http://browserify.org) and
+[brfs](http://github.com/substack/brfs):
+
+```
+$ browserify -t brfs browser.js > static/bundle.js
+```
+
+And that's it! Now we can populate `data.txt` with some silly data:
+
+```
+$ echo '{"who":"substack","message":"beep boop."}' >> data.txt
+$ echo '{"who":"zoltar","message":"COWER PUNY HUMANS"}' >> data.txt
+```
+
+then spin up the server:
+
+```
+$ node server.js
+```
+
+then navigate to `localhost:8000` where we will see our content. If we add some
+more content:
+
+```
+$ echo '{"who":"substack","message":"oh hello."}' >> data.txt
+$ echo '{"who":"zoltar","message":"HEAR ME!"}' >> data.txt
+```
+
+then the page updates automatically with the realtime updates, hooray!
+
+We're now using exactly the same rendering logic on both the client and the
+server to serve up SEO-friendly, indexable realtime content. Hooray!

0 comments on commit a974c63

Please sign in to comment.