Permalink
Browse files

refactor: turns out that the whole server interaction couldnt possibl…

…y work because it didnt take into account concurrent connections. so, lots of changes, good thing it was caught before release
  • Loading branch information...
Zolmeister committed May 8, 2015
1 parent e7ee1be commit 87fdfa82d0da7583a5473c57b4d1b1f6599019b1
Showing with 396 additions and 714 deletions.
  1. +1 −2 package.json
  2. +0 −48 src/cookies.coffee
  3. +44 −0 src/render_to_string.coffee
  4. +55 −134 src/server.coffee
  5. +18 −29 src/state_factory.coffee
  6. +19 −2 src/z.coffee
  7. +2 −1 src/zorium.coffee
  8. +118 −285 test/zorium.coffee
  9. +139 −213 test/zorium_server.coffee
@@ -37,16 +37,15 @@
"merge-stream": "^0.1.7",
"mocha": "^2.2.4",
"promiz": "^1.0.3",
"qs": "^2.4.1",
"rewire": "^2.3.1",
"rewire-webpack": "^1.0.0",
"transform-loader": "^0.2.1",
"webpack": "^1.8.4"
},
"dependencies": {
"coffee-script": "^1.9.2",
"cookie": "^0.1.2",
"lodash": "^3.6.0",
"qs": "^2.4.1",
"routes": "^2.0.0",
"rx-lite": "^2.5.2",
"vdom-to-html": "^2.0.0",

This file was deleted.

Oops, something went wrong.
@@ -0,0 +1,44 @@
_ = require 'lodash'
Rx = require 'rx-lite'
toHTML = require 'vdom-to-html'
z = require './z'
StateFactory = require './state_factory'
Promise = if window?
window.Promise
else
_promiz = 'promiz'
require _promiz
module.exports = (tree) ->
new Promise (resolve) ->
# for unbinding
allStates = []
states = []
disposables = []
listener = ->
z._startRecordingStates()
z tree
states = z._getRecordedStates()
allStates = allStates.concat states
z._stopRecordingStates()
_.map states, (state) ->
unless state._isSubscribing()
state._bind_subscriptions()
disposables.push state.subscribe listener
setTimeout ->
finish()
finish = ->
isDone = _.every states, (state) ->
state._isFulfilled()
if isDone
result = z tree
_.map disposables, (disposable) -> disposable.dispose()
_.map allStates, (state) -> state._unbind_subscriptions()
resolve toHTML result
listener()
@@ -1,15 +1,11 @@
_ = require 'lodash'
toHTML = require 'vdom-to-html'
z = require './z'
render = require './render'
StateFactory = require './state_factory'
cookies = require './cookies'
isSimpleClick = require './is_simple_click'
ev = require './ev'
SERVER_TIMEOUT_MS = 250
getCurrentPath = (mode) ->
hash = window.location.hash.slice(1)
pathname = window.location.pathname
@@ -31,16 +27,6 @@ setPath = (path, mode, isReplacement) ->
class Server
constructor: ->
@events = {}
@$$root = null
@mode = if window?.history?.pushState then 'pathname' else 'hash'
@currentPath = null
@isRedrawScheduled = false
@animationRequestId = null
@$root = null
@status = null # server only
@req = null # server only
# coffeelint: disable=missing_fat_arrows
@Redirect = ({path}) ->
@name = 'redirect'
@@ -50,106 +36,42 @@ class Server
@Redirect.prototype = new Error()
# coffeelint: enable=missing_fat_arrows
if window?
StateFactory.onAnyUpdate =>
if @$root
@go @currentPath
# used for full-page rendering
@globalRoot = document.getElementById 'zorium-root'
unless @globalRoot
@globalRoot = document.createElement 'div'
@globalRoot.id = 'zorium-root'
document.body.appendChild @globalRoot
# some browsers erroneously call popstate on intial page load (iOS Safari)
# We need to ignore that first event.
# https://code.google.com/p/chromium/issues/detail?id=63040
window.addEventListener 'popstate', (e) =>
if @currentPath
setTimeout @go
setStatus: (@status) =>
if window?
throw new Error 'z.server.setStatus() called client-side'
null
setCookie: cookies.set
getCookie: cookies.get
getReq: =>
if window?
throw new Error 'z.server.getReq() called client-side'
@req
factoryToMiddleware: (factory) =>
handleRenderError = (err, req, res, next) =>
if err instanceof @Redirect
return res.redirect err.path
else
return next err
setResCookies = (res, cookies) ->
_.map cookies.getConstructors(), (config, key) ->
res.cookie key, config.value, config.opts
(req, res, next) =>
# Reset state between requests
@setStatus 200
@req = req
cookies.reset()
StateFactory.reset()
hasResolved = false
StateFactory.onError (err) ->
if _.isPlainObject err
err = new Error JSON.stringify err
next err
cookies.populate req.headers?.cookie
$root = factory()
# FIXME
# timeout = setTimeout =>
# @emit 'timeout', {req}
# resolve()
# , SERVER_TIMEOUT_MSgd
resolve = =>
if hasResolved
return
hasResolved = true
# FIXME
# clearTimeout timeout
try
tree = z $root, {
path: req.url
}
setResCookies(res, cookies)
res.status(@status).send '<!DOCTYPE html>' + toHTML tree
catch err
setResCookies(res, cookies)
handleRenderError(err, req, res, next)
# Initialize tree, kicking off async fetches
try
z $root, {
path: req.url
}
unless window?
return
StateFactory.onNextAllSettlemenmt resolve
@events = {}
@$$root = null
@mode = if window?.history?.pushState then 'pathname' else 'hash'
@currentPath = null
@isRedrawScheduled = false
@animationRequestId = null
@$root = null
catch err
hasResolved = true
setResCookies(res, cookies)
handleRenderError(err, req, res, next)
StateFactory.onAnyUpdate =>
if @$root
@go @currentPath
# used for full-page rendering
@globalRoot = document.getElementById 'zorium-root'
unless @globalRoot
@globalRoot = document.createElement 'div'
@globalRoot.id = 'zorium-root'
document.body.appendChild @globalRoot
# some browsers erroneously call popstate on intial page load (iOS Safari)
# We need to ignore that first event.
# https://code.google.com/p/chromium/issues/detail?id=63040
window.addEventListener 'popstate', (e) =>
if @currentPath
setTimeout @go
config: ({mode, $root, $$root}) =>
unless window?
throw new Error 'config called server-side'
config: ({mode, factory, $$root}) =>
@mode = mode or @mode
@$root = factory?() or @$root
@$root = $root or @$root
@$$root = $$root or @$$root
link: (node) =>
@@ -165,23 +87,6 @@ class Server
return node
render: (props) =>
try
tree = z @$root, props
catch err
if err instanceof @Redirect
return @go err.path
else throw err
# Because the DOM doesn't let us directly manipulate top-level elements
# We have to standardize a hack around it
$root = if @$$root is document \
then @globalRoot \
else @$$root
render $root, tree
go: (path) =>
unless window?
throw new Error 'z.server.go() called server-side'
@@ -200,18 +105,36 @@ class Server
path: path
}
renderOrRedirect = (props) =>
try
tree = z @$root, props
catch err
if err instanceof @Redirect
return @go err.path
else throw err
# Because the DOM doesn't let us directly manipulate top-level elements
# We have to standardize a hack around it
$root = if @$$root is document \
then @globalRoot \
else @$$root
render $root, tree
if not isRedraw
@currentPath = path
setPath path, @mode, hasRouted
@emit 'go', {path}
@render(props)
renderOrRedirect(props)
else
@isRedrawScheduled = true
@animationRequestId = window.requestAnimationFrame =>
@isRedrawScheduled = false
@render(props)
renderOrRedirect(props)
on: (name, fn) =>
unless window?
throw new Error 'z.server.on() called server-side'
(@events[name] = @events[name] or []).push(fn)
emit: (name) =>
@@ -220,6 +143,9 @@ class Server
fn.apply null, args
off: (name, fn) =>
unless window?
throw new Error 'z.server.off() called server-side'
@events[name] = _.without(@events[name], fn)
server = new Server()
@@ -229,10 +155,5 @@ module.exports = {
go: server.go
link: server.link
config: server.config
setStatus: server.setStatus
setCookie: server.setCookie
getCookie: server.getCookie
getReq: server.getReq
factoryToMiddleware: server.factoryToMiddleware
Redirect: server.Redirect
}
Oops, something went wrong.

0 comments on commit 87fdfa8

Please sign in to comment.