From bae31831fe79805be146cf6d0754a791da60aec7 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 20 Jun 2016 15:11:28 +0100 Subject: [PATCH 1/2] subscriptions: load on DOM ready --- index.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 6c6a0f2..42028cb 100644 --- a/index.js +++ b/index.js @@ -81,14 +81,17 @@ function choo () { // subscriptions are loaded after sendAction() is called // because they both need access to send() and can't - // react to actions (read-only) - _models.forEach(function (model) { - if (model.subscriptions) { - assert.ok(Array.isArray(model.subscriptions), 'subs must be an array') - model.subscriptions.forEach(function (sub) { - sub(send) - }) - } + // react to actions (read-only) - also wait on DOM to + // be loaded + document.addEventListener('DOMContentLoaded', function () { + _models.forEach(function (model) { + if (model.subscriptions) { + assert.ok(Array.isArray(model.subscriptions), 'subs must be an arr') + model.subscriptions.forEach(function (sub) { + sub(send) + }) + } + }) }) // If an id is provided, the application will rehydrate From 9486df4725c3c1942eacfb6f0fa7c43b31fcf9e5 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 20 Jun 2016 15:56:42 +0100 Subject: [PATCH 2/2] examples: add sse --- README.md | 2 +- examples/sse/client.js | 46 +++++++++++++++++++++++++++++++ examples/sse/package.json | 14 ++++++++++ examples/sse/server.js | 55 ++++++++++++++++++++++++++++++++++++++ examples/sse/views/main.js | 14 ++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 examples/sse/client.js create mode 100644 examples/sse/package.json create mode 100644 examples/sse/server.js create mode 100644 examples/sse/views/main.js diff --git a/README.md b/README.md index 8d952d2..b589d8a 100644 --- a/README.md +++ b/README.md @@ -397,7 +397,7 @@ app.model({ } ], effects: { - 'sse:close': () => stream.close() + 'sse:close': () => stream.close(), 'app:error': (state, event) => console.error(`error: ${event.payload}`), 'app:print': (state, event) => console.log(`sse: ${event.payload}`) } diff --git a/examples/sse/client.js b/examples/sse/client.js new file mode 100644 index 0000000..a386413 --- /dev/null +++ b/examples/sse/client.js @@ -0,0 +1,46 @@ +const choo = require('../../') + +const app = choo() +app.model(createModel()) +app.router((route) => [ + route('/', mainView) +]) + +const tree = app.start() +document.body.appendChild(tree) + +function mainView (params, state, send) { + return choo.view` +
${state.logger.msg}
+ ` +} + +function createModel () { + const stream = new window.EventSource('/sse') + return { + namespace: 'logger', + state: { + msg: '' + }, + subscriptions: [ + function (send) { + stream.onerror = (e) => { + send('logger:error', { payload: JSON.stringify(e) }) + } + stream.onmessage = (e) => { + const msg = JSON.parse(e.data).message + send('logger:print', { payload: msg }) + } + } + ], + reducers: { + 'print': (action, state) => { + return ({ msg: state.msg + ' ' + action.payload }) + } + }, + effects: { + close: () => stream.close(), + error: (action, state) => console.error(`error: ${action.payload}`) + } + } +} diff --git a/examples/sse/package.json b/examples/sse/package.json new file mode 100644 index 0000000..4e94c61 --- /dev/null +++ b/examples/sse/package.json @@ -0,0 +1,14 @@ +{ + "name": "http", + "private": true, + "main": "client.js", + "scripts": { + "start": "NODE_ENV=development node server.js" + }, + "dependencies": { + "bankai": "^2.0.2", + "browserify": "^13.0.1", + "server-router": "^2.1.0", + "sse": "0.0.6" + } +} diff --git a/examples/sse/server.js b/examples/sse/server.js new file mode 100644 index 0000000..6854685 --- /dev/null +++ b/examples/sse/server.js @@ -0,0 +1,55 @@ +const serverRouter = require('server-router') +const browserify = require('browserify') +const bankai = require('bankai') +const http = require('http') +const SSE = require('sse') + +const clients = [] +const PORT = 8080 + +const server = http.createServer(createRouter()) +server.listen(PORT, () => { + process.stdout.write(`listening on port ${PORT}\n`) + var sse = new SSE(server) + + // code adapted from: https://github.com/markbrown4/server-sent-events-demo + sse.on('connection', (stream) => { + clients.push(stream) + console.log('Opened connection 🎉') + + var json = JSON.stringify({ message: 'Gotcha' }) + stream.send(json) + console.log('Sent: ' + json) + + stream.on('close', () => { + clients.splice(clients.indexOf(stream), 1) + console.log('Closed connection 😱') + }) + }) +}) + +// emit data every 1.5 seconds +setInterval(() => { + var json = JSON.stringify({ message: 'Hello hello!' }) + clients.forEach((stream) => { + stream.send(json) + console.log('Sent: ' + json) + }) +}, 1500) + +function createRouter () { + const router = serverRouter('/404') + + const html = bankai.html({ css: false }) + router.on('/', (req, res) => html(req, res).pipe(res)) + + const js = bankai.js(browserify, require.resolve('./client.js')) + router.on('/bundle.js', (req, res) => js(req, res).pipe(res)) + + router.on('/404', (req, res) => { + res.statusCode = 404 + res.end('{ "message": "the server is confused" }') + }) + + return router +} diff --git a/examples/sse/views/main.js b/examples/sse/views/main.js new file mode 100644 index 0000000..4d0d435 --- /dev/null +++ b/examples/sse/views/main.js @@ -0,0 +1,14 @@ +const choo = require('../../../') + +module.exports = function (params, state, send) { + const error = state.app.error[0] + const title = state.api.title + return choo.view` +
+

${title}

+

Latest error: ${error}

+ + +
+ ` +}