choo-lazy-view
Advanced tools
Comparing version 0.3.0-0 to 0.3.0-1
35
index.js
@@ -8,3 +8,2 @@ var assert = require('assert') | ||
Component.call(this, id) | ||
this.view = view || null | ||
} | ||
@@ -18,18 +17,9 @@ | ||
var id = 'view-' + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1) | ||
var queue = this.queue = this.queue || [] | ||
var view = null | ||
if (typeof window === 'undefined') { | ||
queue.push(fn(function (err, response) { | ||
if (err) assert.fail('choo-lazy-view: ' + err.message) | ||
view = response | ||
})) | ||
} | ||
return function (state, emit) { | ||
var cached = state.cache(Self, id, view) | ||
var cached = state.cache(Self, id) | ||
if (!cached.view) { | ||
emit('choo-lazy-view:fetch', id) | ||
fn(function (err, view) { | ||
var promise = fn(function (err, view) { | ||
if (err) return emit('choo-lazy-view:error', err) | ||
@@ -40,2 +30,15 @@ emit('choo-lazy-view:done', id, view) | ||
}) | ||
var prefetch = state.prefetch || state._experimental_prefetch | ||
if (prefetch) { | ||
promise = promise.then(function (view) { | ||
// account for view issuing more prefetches | ||
var res = cached.render(state, emit) | ||
// defer to nested prefetches issued by above render | ||
var nested = prefetch.filter(function (p) { return p !== promise }) | ||
return Promise.all(nested).then(function () { return res }) | ||
}) | ||
prefetch.push(promise) | ||
return promise | ||
} | ||
} | ||
@@ -46,4 +49,6 @@ | ||
if (loader) return loader | ||
assert(typeof window !== 'undefined', 'choo-lazy-view: loader is required when not using prefetch') | ||
if (typeof Self.selector === 'string') return document.querySelector(Self.selector) | ||
if (Self.selector instanceof window.HTMLElement) return Self.selector | ||
if (Self.selector instanceof window.Element) return Self.selector | ||
assert.fail('choo-lazy-view: could not mount loader') | ||
@@ -55,5 +60,3 @@ } | ||
this.selector = selector | ||
return Promise.all(this.queue).then(function () { | ||
return app.mount(selector) | ||
}) | ||
return app.mount(selector) | ||
} | ||
@@ -60,0 +63,0 @@ |
{ | ||
"name": "choo-lazy-view", | ||
"version": "0.3.0-0", | ||
"version": "0.3.0-1", | ||
"description": "Lazily fetch view when needed", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -8,3 +8,5 @@ # choo-lazy-view | ||
Lazily load views as the router invokes them. Built for [split-require][split-require] but should work with any software with a similar callback signature. | ||
Lazily load views as the router invokes them. Works great with dynamic import or | ||
[split-require][split-require] but should work with any software with a promise | ||
or callback interface. | ||
@@ -21,5 +23,9 @@ ## Usage | ||
app.route('/', main) | ||
app.route('/a', LazyView.create((callback) => splitRequire('./a', callback))) | ||
app.route('/b', LazyView.create((callback) => splitRequire('./b', callback))) | ||
// using dynamic import | ||
app.route('/some-page', LazyView.create(() => import('./a'))) | ||
// or using split-require | ||
app.route('/another-page', LazyView.create((cb) => splitRequire('./b', cb))) | ||
module.exports = LazyView.mount(app, 'body') | ||
@@ -39,19 +45,32 @@ | ||
## API | ||
The module exposes a [Nanocomponent][nanocomponent] class with two static methods which are used for wrapping your views and `choo.mount`. | ||
The module exposes a [Nanocomponent][nanocomponent] class with two static | ||
methods which are used for wrapping your views and `choo.mount`. | ||
### `LazyView.create(callback, loader?)` | ||
Accepts a callback and an optional loader view. The callback will be invoked when the returned function is called upon (called immediately in node). The callback, in turn, should load the required view and relay it's response (or error) back to the caller. | ||
Accepts a callback and an optional loader view. The callback will be invoked | ||
when the returned function is called upon by the router. The callback, in turn, | ||
should load the required view and relay it's response (or error) back to the | ||
caller. This can be done either with a `Promise` or with the supplied callback. | ||
```javascript | ||
app.route('/page', LazyView.create(function (callback) { | ||
fetchViewSomehow(callback) | ||
// using promise | ||
app.route('/my-page', LazyView.create(function () { | ||
return fetchViewPromise() | ||
})) | ||
// using the callback | ||
app.route('/another-page', LazyView.create(function (callback) { | ||
fetchViewCallback(callback) | ||
})) | ||
``` | ||
The second argument is optional and should be a function or a DOM node which will be displayed while loading. By default, the node used to mount the application in the DOM is used as loader (meaning the view remains unchanged while loading). | ||
The second argument is optional and should be a function or a DOM node which | ||
will be displayed while loading. By default, the node used to mount the | ||
application in the DOM is used as loader (meaning the view remains unchanged | ||
while loading). | ||
```javascript | ||
app.route('/a', LazyView.create( | ||
(callback) => splitRequire('./a', callback), | ||
(state, emit) => html`<h1>Loading view…</h1>` | ||
() => import('./my-view'), | ||
(state, emit) => html`<body>Loading view…</body>` | ||
)) | ||
@@ -61,13 +80,13 @@ ``` | ||
### `LazyView.mount(app, selector)` | ||
Wrapper function for `app.mount`. Returns a promise which resolves once the application is ready. Needed because split-require resolves modules asynchronously | ||
Wrapper function for `app.mount` which stores the selector internally to use as | ||
fallback loader while fetching views. | ||
```javascript | ||
// server.js | ||
Promise.resolve(require('./index')).then(function (app) { | ||
var html = app.toString('/a') | ||
}) | ||
```diff | ||
- module.exports = app.mount('body') | ||
+ module.exports = LazyView.mount(app, 'body') | ||
``` | ||
### Extending LazyView | ||
You may extend on LazyView to add a shared framework wrapper, e.g. a header, footer, etc. | ||
You may extend on the LazyView component to add a shared framework wrapper, e.g. | ||
a header and footer. | ||
@@ -85,5 +104,5 @@ ```javascript | ||
<body> | ||
${state.cache(Header, 'header')} | ||
${state.cache(Header, 'header').render()} | ||
${super.createElement(state, emit)} | ||
${state.cache(Footer, 'footer')} | ||
${state.cache(Footer, 'footer').render()} | ||
</body> | ||
@@ -98,3 +117,2 @@ ` | ||
var choo = require('choo') | ||
var splitRequire = require('split-require') | ||
var View = require('./components/view') | ||
@@ -104,3 +122,3 @@ | ||
app.route('/', View.create((callback) => splitRequire('./views/home', callback))) | ||
app.route('/', View.create(() => import('./views/home'))) | ||
@@ -119,2 +137,5 @@ module.exports = View.mount(app, 'body') | ||
#### `choo-lazy-view:error` | ||
When the view fails to load. | ||
[choo]: https://github.com/choojs/choo | ||
@@ -121,0 +142,0 @@ [nanocomponent]: https://github.com/choojs/nanocomponent |
8051
74
146