Skip to content

Commit 2cd3378

Browse files
committed
async route loading
1 parent 948a4f8 commit 2cd3378

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

index.js

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ function Choo (opts) {
4242
this._hasWindow = typeof window !== 'undefined'
4343
this._createLocation = nanolocation
4444
this._cache = opts.cache
45+
this._asyncProxy = null // proxy for async routes
46+
this._asyncRoutes = {}
4547
this._loaded = false
4648
this._stores = []
4749
this._tree = null
@@ -76,10 +78,66 @@ function Choo (opts) {
7678

7779
Choo.prototype.route = function (route, handler) {
7880
assert.equal(typeof route, 'string', 'choo.route: route should be type string')
79-
assert.equal(typeof handler, 'function', 'choo.handler: route should be type function')
81+
assert.equal(typeof handler, 'function', 'choo.route: handler should be type function')
8082
this.router.on(route, handler)
8183
}
8284

85+
// Register a route to be loaded asynchronously.
86+
Choo.prototype.asyncRoute = function (route, load) {
87+
assert.equal(typeof route, 'string', 'choo.asyncRoute: asyncRoute should be type string')
88+
assert.equal(typeof handler, 'function', 'choo.asyncRoute: route should be type function')
89+
90+
var IDLE = 0
91+
var LOADING = 1
92+
var LOADED = 2
93+
94+
var loadingState = IDLE
95+
var renderRoute = null
96+
var view = null
97+
var self = this
98+
99+
this.route(route, function (state, emit) {
100+
if (!self._asyncProxy) self._initAsyncProxy()
101+
// Begin loading the bundle on the first call
102+
if (loadingState === IDLE) {
103+
emit('choo:async-route-start', state.route)
104+
renderRoute = state.route
105+
loadingState = LOADING
106+
107+
var p = load(onload)
108+
assert(p && p.then, 'choo.asyncRoute: async route should return a Promise')
109+
p.then(onload.bind(null, null), onload)
110+
return self._asyncProxy
111+
} else if (loadingState === LOADING) {
112+
return self._asyncProxy
113+
} else {
114+
// loadingState === LOADED
115+
return view(state, emit)
116+
}
117+
118+
function onload (err, _view) {
119+
if (err) {
120+
emit('error', err)
121+
loadingState = IDLE
122+
return
123+
}
124+
125+
emit('choo:async-route-end', renderRoute, _view)
126+
loadingState = LOADED
127+
view = _view
128+
129+
// Only rerender if we are still on the same route
130+
if (state.route === renderRoute) emit('render')
131+
}
132+
})
133+
}
134+
135+
Choo.prototype._initAsyncProxy = function () {
136+
var tagName = this._tree ? this._tree.nodeName : 'body'
137+
this._asyncProxy = document.createElement(tagName)
138+
this._asyncProxy.isSameNode = function () { return true }
139+
}
140+
83141
Choo.prototype.use = function (cb) {
84142
assert.equal(typeof cb, 'function', 'choo.use: cb should be type function')
85143
var self = this

0 commit comments

Comments
 (0)