From 2cd33782b4a444cd148875fc8bd5dfdbea92555d Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Wed, 4 Apr 2018 16:16:29 +0200 Subject: [PATCH 1/4] async route loading --- index.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 79a7c525..059d7570 100644 --- a/index.js +++ b/index.js @@ -42,6 +42,8 @@ function Choo (opts) { this._hasWindow = typeof window !== 'undefined' this._createLocation = nanolocation this._cache = opts.cache + this._asyncProxy = null // proxy for async routes + this._asyncRoutes = {} this._loaded = false this._stores = [] this._tree = null @@ -76,10 +78,66 @@ function Choo (opts) { Choo.prototype.route = function (route, handler) { 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.route: handler should be type function') this.router.on(route, handler) } +// Register a route to be loaded asynchronously. +Choo.prototype.asyncRoute = function (route, load) { + assert.equal(typeof route, 'string', 'choo.asyncRoute: asyncRoute should be type string') + assert.equal(typeof handler, 'function', 'choo.asyncRoute: route should be type function') + + var IDLE = 0 + var LOADING = 1 + var LOADED = 2 + + var loadingState = IDLE + var renderRoute = null + var view = null + var self = this + + this.route(route, function (state, emit) { + if (!self._asyncProxy) self._initAsyncProxy() + // Begin loading the bundle on the first call + if (loadingState === IDLE) { + emit('choo:async-route-start', state.route) + renderRoute = state.route + loadingState = LOADING + + var p = load(onload) + assert(p && p.then, 'choo.asyncRoute: async route should return a Promise') + p.then(onload.bind(null, null), onload) + return self._asyncProxy + } else if (loadingState === LOADING) { + return self._asyncProxy + } else { + // loadingState === LOADED + return view(state, emit) + } + + function onload (err, _view) { + if (err) { + emit('error', err) + loadingState = IDLE + return + } + + emit('choo:async-route-end', renderRoute, _view) + loadingState = LOADED + view = _view + + // Only rerender if we are still on the same route + if (state.route === renderRoute) emit('render') + } + }) +} + +Choo.prototype._initAsyncProxy = function () { + var tagName = this._tree ? this._tree.nodeName : 'body' + this._asyncProxy = document.createElement(tagName) + this._asyncProxy.isSameNode = function () { return true } +} + Choo.prototype.use = function (cb) { assert.equal(typeof cb, 'function', 'choo.use: cb should be type function') var self = this From 2ff9f3d134529989b0d41fa9dd23ccf9728ba089 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Wed, 4 Apr 2018 16:58:56 +0200 Subject: [PATCH 2/4] experimental async --- example/index.js | 3 +++ example/package.json | 3 ++- index.js | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/example/index.js b/example/index.js index 117d05e3..e6c15337 100644 --- a/example/index.js +++ b/example/index.js @@ -1,3 +1,4 @@ +var split = require('split-require') var css = require('sheetify') var choo = require('../') @@ -15,4 +16,6 @@ app.route('#active', require('./views/main')) app.route('#completed', require('./views/main')) app.route('*', require('./views/main')) +app.experimentalAsyncRoute('/async', () => split('./views/main.js')) + module.exports = app.mount('body') diff --git a/example/package.json b/example/package.json index fdd34598..3e82b553 100644 --- a/example/package.json +++ b/example/package.json @@ -15,7 +15,8 @@ "todomvc-common": "^1.0.3" }, "devDependencies": { - "bankai": "^9.0.0-rc6", + "bankai": "9.10.4", + "split-require": "^3.1.0", "standard": "^9.0.1" } } diff --git a/index.js b/index.js index 059d7570..d08d5941 100644 --- a/index.js +++ b/index.js @@ -83,7 +83,7 @@ Choo.prototype.route = function (route, handler) { } // Register a route to be loaded asynchronously. -Choo.prototype.asyncRoute = function (route, load) { +Choo.prototype.experimentalAsyncRoute = function (route, load) { assert.equal(typeof route, 'string', 'choo.asyncRoute: asyncRoute should be type string') assert.equal(typeof handler, 'function', 'choo.asyncRoute: route should be type function') From afd1c185a7e1048cf176a6ddd329b30169e2e00a Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Wed, 4 Apr 2018 17:03:19 +0200 Subject: [PATCH 3/4] fix async rendering --- example/index.js | 11 +++++++++-- index.js | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/example/index.js b/example/index.js index e6c15337..eb7eaabf 100644 --- a/example/index.js +++ b/example/index.js @@ -1,6 +1,7 @@ -var split = require('split-require') +// var split = require('split-require') var css = require('sheetify') var choo = require('../') +var html = require('choo/html') css('todomvc-common/base.css') css('todomvc-app-css/index.css') @@ -16,6 +17,12 @@ app.route('#active', require('./views/main')) app.route('#completed', require('./views/main')) app.route('*', require('./views/main')) -app.experimentalAsyncRoute('/async', () => split('./views/main.js')) +app.experimentalAsyncRoute('/async', () => Promise.resolve(function (state, emit) { + return html` + + Async rendering. + + ` +})) module.exports = app.mount('body') diff --git a/index.js b/index.js index d08d5941..1838a45d 100644 --- a/index.js +++ b/index.js @@ -83,9 +83,9 @@ Choo.prototype.route = function (route, handler) { } // Register a route to be loaded asynchronously. -Choo.prototype.experimentalAsyncRoute = function (route, load) { +Choo.prototype.experimentalAsyncRoute = function (route, loader) { assert.equal(typeof route, 'string', 'choo.asyncRoute: asyncRoute should be type string') - assert.equal(typeof handler, 'function', 'choo.asyncRoute: route should be type function') + assert.equal(typeof loader, 'function', 'choo.asyncRoute: loader should be type function') var IDLE = 0 var LOADING = 1 @@ -104,7 +104,7 @@ Choo.prototype.experimentalAsyncRoute = function (route, load) { renderRoute = state.route loadingState = LOADING - var p = load(onload) + var p = loader(onload) assert(p && p.then, 'choo.asyncRoute: async route should return a Promise') p.then(onload.bind(null, null), onload) return self._asyncProxy From 9d490affc6f86aae9807327bd158c13389fd11ac Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Wed, 4 Apr 2018 17:15:44 +0200 Subject: [PATCH 4/4] fix async route stuff --- example/index.js | 11 ++--------- example/views/async.js | 11 +++++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 example/views/async.js diff --git a/example/index.js b/example/index.js index eb7eaabf..4e5a17aa 100644 --- a/example/index.js +++ b/example/index.js @@ -1,7 +1,6 @@ -// var split = require('split-require') +var split = require('split-require') var css = require('sheetify') var choo = require('../') -var html = require('choo/html') css('todomvc-common/base.css') css('todomvc-app-css/index.css') @@ -17,12 +16,6 @@ app.route('#active', require('./views/main')) app.route('#completed', require('./views/main')) app.route('*', require('./views/main')) -app.experimentalAsyncRoute('/async', () => Promise.resolve(function (state, emit) { - return html` - - Async rendering. - - ` -})) +app.experimentalAsyncRoute('/async', () => split('./views/async')) module.exports = app.mount('body') diff --git a/example/views/async.js b/example/views/async.js new file mode 100644 index 00000000..d31b5455 --- /dev/null +++ b/example/views/async.js @@ -0,0 +1,11 @@ +var html = require('bel') // cannot require choo/html because it's a nested repo + +module.exports = mainView + +function mainView (state, emit) { + return html` + + Async route + + ` +}