Separate route matching from rendering (#613)

- This fixes https://github.com/choojs/choo/issues/530
- Adds support for wayfarer/nanorouter subrouters
This commit is contained in:
Marc Bachmann
2018-01-17 23:58:42 +01:00
committed by Yoshua Wuyts
parent 5a6bf802ce
commit cf8c316189
2 changed files with 35 additions and 26 deletions
+34 -25
View File
@@ -43,8 +43,9 @@ function Choo (opts) {
this._tree = null this._tree = null
// properties that are part of the API // properties that are part of the API
this.router = nanorouter({ curry: true }) this.router = nanorouter()
this.emitter = nanobus('choo.emit') this.emitter = nanobus('choo.emit')
this.emit = this.emitter.emit.bind(this.emitter)
var events = { events: this._events } var events = { events: this._events }
if (this._hasWindow) { if (this._hasWindow) {
@@ -68,20 +69,7 @@ function Choo (opts) {
Choo.prototype.route = function (route, handler) { Choo.prototype.route = function (route, handler) {
assert.equal(typeof route, 'string', 'choo.route: route should be type string') assert.equal(typeof route, 'string', 'choo.route: route should be type string')
assert.equal(typeof handler, 'function', 'choo.handler: route should be type function') assert.equal(typeof handler, 'function', 'choo.handler: route should be type function')
this.router.on(route, handler)
var self = this
this.router.on(route, function (params) {
return function () {
self.state.params = params
self.state.route = route
var routeTiming = nanotiming("choo.route('" + route + "')")
var res = handler(self.state, function (eventName, data) {
self.emitter.emit.apply(self.emitter, arguments)
})
routeTiming()
return res
}
})
} }
Choo.prototype.use = function (cb) { Choo.prototype.use = function (cb) {
@@ -99,7 +87,7 @@ Choo.prototype.start = function () {
var self = this var self = this
if (this._historyEnabled) { if (this._historyEnabled) {
this.emitter.prependListener(this._events.NAVIGATE, function () { this.emitter.prependListener(this._events.NAVIGATE, function () {
self.state.query = nanoquery(window.location.search) self._matchRoute()
if (self._loaded) { if (self._loaded) {
self.emitter.emit(self._events.RENDER) self.emitter.emit(self._events.RENDER)
setTimeout(scrollToAnchor.bind(null, window.location.hash), 0) setTimeout(scrollToAnchor.bind(null, window.location.hash), 0)
@@ -136,16 +124,13 @@ Choo.prototype.start = function () {
} }
} }
this.state.href = this._createLocation() this._matchRoute()
this.state.query = nanoquery(window.location.search) this._tree = this._prerender(this.state)
this._tree = this.router(this.state.href)
assert.ok(this._tree, 'choo.start: no valid DOM node returned for location ' + this.state.href) assert.ok(this._tree, 'choo.start: no valid DOM node returned for location ' + this.state.href)
this.emitter.prependListener(self._events.RENDER, nanoraf(function () { this.emitter.prependListener(self._events.RENDER, nanoraf(function () {
var renderTiming = nanotiming('choo.render') var renderTiming = nanotiming('choo.render')
var newTree = self._prerender(self.state)
self.state.href = self._createLocation()
var newTree = self.router(self.state.href)
assert.ok(newTree, 'choo.render: no valid DOM node returned for location ' + self.state.href) assert.ok(newTree, 'choo.render: no valid DOM node returned for location ' + self.state.href)
assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.render: The target node <' + assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.render: The target node <' +
@@ -202,9 +187,33 @@ Choo.prototype.toString = function (location, state) {
assert.equal(typeof location, 'string', 'choo.toString: location should be type string') 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') assert.equal(typeof this.state, 'object', 'choo.toString: state should be type object')
this.state.href = location.replace(/\?.+$/, '') this._matchRoute(location)
this.state.query = nanoquery(location) var html = this._prerender(this.state)
var html = this.router(location)
assert.ok(html, 'choo.toString: no valid value returned for the route ' + location) assert.ok(html, 'choo.toString: no valid value returned for the route ' + location)
return html.toString() return html.toString()
} }
Choo.prototype._matchRoute = function (locationOverride) {
var location, queryString
if (locationOverride) {
location = locationOverride.replace(/\?.+$/, '')
queryString = locationOverride
} else {
location = this._createLocation()
queryString = window.location.search
}
var matched = this.router.match(location)
this.state.href = location
this.state.query = nanoquery(queryString)
this.state.route = matched.route
this.state.params = matched.params
this.state._handler = matched.cb
return this.state
}
Choo.prototype._prerender = function (state) {
var routeTiming = nanotiming("choo.prerender('" + state.route + "')")
var res = state._handler(state, this.emit)
routeTiming()
return res
}
+1 -1
View File
@@ -39,7 +39,7 @@
"nanomorph": "^5.1.2", "nanomorph": "^5.1.2",
"nanoquery": "^1.1.0", "nanoquery": "^1.1.0",
"nanoraf": "^3.0.0", "nanoraf": "^3.0.0",
"nanorouter": "^2.0.0", "nanorouter": "^3.0.1",
"nanotiming": "^6.0.0", "nanotiming": "^6.0.0",
"scroll-to-anchor": "^1.0.0", "scroll-to-anchor": "^1.0.0",
"xtend": "^4.0.1" "xtend": "^4.0.1"