54 lines
1.7 KiB
JavaScript
54 lines
1.7 KiB
JavaScript
// Lazy (async) routes — the v8 answer to choojs/choo#653.
|
|||
|
|
//
|
||
|
|
// A lazy route handler loads its view on first match via a native dynamic
|
||
|
|
// import (or any promise-returning loader) and caches it forever after.
|
||
|
|
// In the browser, while the view is loading, the handler renders the
|
||
|
|
// optional loading view — or the PENDING sentinel, which tells choo to
|
||
|
|
// keep whatever is already on screen. When the module arrives the wrapper
|
||
|
|
// emits a render and the real view morphs in. On the server, toStream()
|
||
|
|
// awaits load() before rendering; toString() refuses lazy routes loudly
|
||
|
|
// (the missing server story is what stalled #653 — here both halves ship
|
||
|
|
// together).
|
||
|
|
|
||
|
|
import { equal } from './assert.js'
|
||
|
|
|
||
|
|
// Sentinel: "keep the current tree, a view is on its way"
|
||
|
|
export const PENDING = { __chooPending: true }
|
||
|
|
|
||
|
|
export default function lazy (loader, loading) {
|
||
|
|
equal(typeof loader, 'function', 'choo.lazy: loader should be type function')
|
||
|
|
|
||
|
|
let view = null
|
||
|
|
let promise = null
|
||
|
|
|
||
|
|
function load () {
|
||
|
|
if (!promise) {
|
||
|
|
promise = Promise.resolve(loader()).then(function (mod) {
|
||
|
|
view = (mod && mod.default) || mod
|
||
|
|
equal(typeof view, 'function', 'choo.lazy: loader should resolve to a view function (module default export)')
|
||
|
|
return view
|
||
|
|
})
|
||
|
|
}
|
||
|
|
return promise
|
||
|
|
}
|
||
|
|
|
||
|
|
function lazyView (state, emit) {
|
||
|
|
if (view) return view(state, emit)
|
||
|
|
|
||
|
|
load().then(function () {
|
||
|
|
emit(state.events.RENDER)
|
||
|
|
}, function (err) {
|
||
|
|
// surface load failures instead of hanging on the loading view
|
||
|
|
emit('error', err)
|
||
|
|
throw err
|
||
|
|
})
|
||
|
|
|
||
|
|
if (loading) return loading(state, emit)
|
||
|
|
return PENDING
|
||
|
|
}
|
||
|
|
|
||
|
|
lazyView.__lazy = true
|
||
|
|
lazyView.load = load
|
||
|
|
return lazyView
|
||
|
|
}
|