choo components (#639)
* add components * example: componentize header * fix choo SSR * example: componentize footer * example: fix footer * update component cache asserts * componentize todos * reorder example dir * fix example tests * fix dep check test * Add garbage collection of unused components * Apply args when calling identity * update to new component preview * update nanocomponent * fix cache err name * remove static methods from example * restore app.emit() function * public API tests * offset component cache iteration by 2 * whitelist contents of component folder (#643) * allow lru number arg * fix lint typo
This commit is contained in:
@@ -11,6 +11,8 @@ var nanobus = require('nanobus')
|
||||
var assert = require('assert')
|
||||
var xtend = require('xtend')
|
||||
|
||||
var Cache = require('./component/cache')
|
||||
|
||||
module.exports = Choo
|
||||
|
||||
var HISTORY_OBJECT = {}
|
||||
@@ -39,25 +41,30 @@ function Choo (opts) {
|
||||
this._hrefEnabled = opts.href === undefined ? true : opts.href
|
||||
this._hasWindow = typeof window !== 'undefined'
|
||||
this._createLocation = nanolocation
|
||||
this._cache = opts.cache
|
||||
this._loaded = false
|
||||
this._stores = []
|
||||
this._tree = null
|
||||
|
||||
// properties that are part of the API
|
||||
this.router = nanorouter()
|
||||
this.emitter = nanobus('choo.emit')
|
||||
this.emit = this.emitter.emit.bind(this.emitter)
|
||||
|
||||
var events = { events: this._events }
|
||||
// state
|
||||
var _state = {
|
||||
events: this._events,
|
||||
components: {}
|
||||
}
|
||||
if (this._hasWindow) {
|
||||
this.state = window.initialState
|
||||
? xtend(window.initialState, events)
|
||||
: events
|
||||
? xtend(window.initialState, _state)
|
||||
: _state
|
||||
delete window.initialState
|
||||
} else {
|
||||
this.state = events
|
||||
this.state = _state
|
||||
}
|
||||
|
||||
// properties that are part of the API
|
||||
this.router = nanorouter({ curry: true })
|
||||
this.emitter = nanobus('choo.emit')
|
||||
this.emit = this.emitter.emit.bind(this.emitter)
|
||||
|
||||
// listen for title changes; available even when calling .toString()
|
||||
if (this._hasWindow) this.state.title = document.title
|
||||
this.emitter.prependListener(this._events.DOMTITLECHANGE, function (title) {
|
||||
@@ -76,11 +83,11 @@ Choo.prototype.route = function (route, handler) {
|
||||
Choo.prototype.use = function (cb) {
|
||||
assert.equal(typeof cb, 'function', 'choo.use: cb should be type function')
|
||||
var self = this
|
||||
this._stores.push(function () {
|
||||
this._stores.push(function (state) {
|
||||
var msg = 'choo.use'
|
||||
msg = cb.storeName ? msg + '(' + cb.storeName + ')' : msg
|
||||
var endTiming = nanotiming(msg)
|
||||
cb(self.state, self.emitter, self)
|
||||
cb(state, self.emitter, self)
|
||||
endTiming()
|
||||
})
|
||||
}
|
||||
@@ -128,8 +135,9 @@ Choo.prototype.start = function () {
|
||||
}
|
||||
}
|
||||
|
||||
this._setCache(this.state)
|
||||
this._stores.forEach(function (initStore) {
|
||||
initStore()
|
||||
initStore(self.state)
|
||||
})
|
||||
|
||||
this._matchRoute()
|
||||
@@ -200,9 +208,10 @@ Choo.prototype.toString = function (location, state) {
|
||||
assert.equal(typeof location, 'string', 'choo.toString: location should be type string')
|
||||
assert.equal(typeof this.state, 'object', 'choo.toString: state should be type object')
|
||||
|
||||
// TODO: pass custom state down to each store.
|
||||
var self = this
|
||||
this._setCache(this.state)
|
||||
this._stores.forEach(function (initStore) {
|
||||
initStore()
|
||||
initStore(self.state)
|
||||
})
|
||||
|
||||
this._matchRoute(location)
|
||||
@@ -236,3 +245,23 @@ Choo.prototype._prerender = function (state) {
|
||||
routeTiming()
|
||||
return res
|
||||
}
|
||||
|
||||
Choo.prototype._setCache = function (state) {
|
||||
var cache = new Cache(state, this.emitter.emit.bind(this.emitter), this._cache)
|
||||
state.cache = renderComponent
|
||||
|
||||
function renderComponent (Component, id) {
|
||||
assert.equal(typeof Component, 'function', 'choo.state.cache: Component should be type function')
|
||||
var args = []
|
||||
for (var i = 0, len = arguments.length; i < len; i++) {
|
||||
args.push(arguments[i])
|
||||
}
|
||||
return cache.render.apply(cache, args)
|
||||
}
|
||||
|
||||
// When the state gets stringified, make sure `state.cache` isn't
|
||||
// stringified too.
|
||||
renderComponent.toJSON = function () {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user