New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

choo-lazy-view

Package Overview
Dependencies
Maintainers
2
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

choo-lazy-view - npm Package Compare versions

Comparing version 0.3.0-1 to 1.0.0

105

index.js

@@ -1,75 +0,56 @@

var assert = require('assert')
var Component = require('nanocomponent')
module.exports = lazy
module.exports.view = view
module.exports.store = store
module.exports = LazyView
function LazyView (id, state, emitter, view) {
Component.call(this, id)
function lazy () {
if (arguments.length === 3) return store.apply(undefined, arguments)
else return view.apply(undefined, arguments)
}
LazyView.create = function (fn, loader) {
assert(typeof fn === 'function', 'choo-lazy-view: fn should be a function')
fn = promisify(fn)
function view (load, loader) {
var init = promisify(load)
var Self = this
var id = 'view-' + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
return function proxy (state, emit) {
if (proxy.render) return proxy.render.call(this, state, emit)
return function (state, emit) {
var cached = state.cache(Self, id)
var p = init().then(function (render) {
// asynchronously render view to account for nested prefetches
if (typeof window === 'undefined') render(state, emit)
proxy.render = render
return render
})
if (!cached.view) {
emit('choo-lazy-view:fetch', id)
var promise = fn(function (err, view) {
if (err) return emit('choo-lazy-view:error', err)
emit('choo-lazy-view:done', id, view)
cached.view = view
emit('render')
})
emit('lazy:load', p)
if (typeof loader === 'function') return loader(state, emit)
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
}
// assuming app has been provided initialState by server side render
var selector = state.selector
if (typeof window === 'undefined') {
// eslint-disable-next-line no-new-wrappers
var str = new String('<' + selector + '></' + selector + '>')
str.__encoded = true
return str
}
if (cached.view) return cached.render(state, emit)
if (typeof loader === 'function') return loader(state, emit)
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.Element) return Self.selector
assert.fail('choo-lazy-view: could not mount loader')
if (typeof selector === 'string') return document.querySelector(selector)
if (selector instanceof window.Element) return selector
throw new Error('choo-lazy-view: loader or server side generated initialState required')
}
}
LazyView.mount = function (app, selector) {
this.selector = selector
return app.mount(selector)
function store (state, emitter, app) {
state.selector = state.selector || app.selector
emitter.on('lazy:load', function (p) {
var prefetch = state.prefetch || state._experimental_prefetch
if (prefetch) prefetch.push(p)
p.then(
emitter.emit.bind(emitter, 'lazy:success'),
emitter.emit.bind(emitter, 'lazy:error')
).then(emitter.emit.bind(emitter, 'render'))
})
}
LazyView.prototype = Object.create(Component.prototype)
LazyView.prototype.constructor = LazyView
LazyView.prototype.update = function () {
return true
}
LazyView.prototype.createElement = function (state, emit) {
assert(this.view, 'choo-lazy-view: cannot render without view')
return this.view(state, emit)
}
// wrap callback function with promise
// fn -> fn
function promisify (fn) {
return function (cb) {
return function () {
return new Promise(function (resolve, reject) {

@@ -81,10 +62,4 @@ var res = fn(function (err, value) {

if (res instanceof Promise) return res.then(resolve, reject)
}).then(done.bind(null, null), done)
function done (err, res) {
if (typeof cb === 'function') cb(err, res)
if (err) throw err
else return res
}
})
}
}
{
"name": "choo-lazy-view",
"version": "0.3.0-1",
"version": "1.0.0",
"description": "Lazily fetch view when needed",

@@ -9,7 +9,2 @@ "main": "index.js",

},
"browserify": {
"transform": [
"unassertify"
]
},
"repository": {

@@ -23,3 +18,4 @@ "type": "git",

"bankai",
"jalla"
"jalla",
"lazy"
],

@@ -35,7 +31,3 @@ "author": "Carl Törnqvist <carl@tornqv.ist>",

"standard": "^11.0.1"
},
"dependencies": {
"nanocomponent": "^6.5.2",
"unassertify": "^2.1.1"
}
}

@@ -9,10 +9,7 @@ # choo-lazy-view

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.
[split-require][split-require] but should work with any promise or callback API.
## Usage
```javascript
var splitRequire = require('split-require')
var LazyView = require('choo-lazy-view')
var html = require('choo/html')
var lazy = require('choo-lazy-view')
var choo = require('choo')

@@ -22,42 +19,29 @@

app.route('/', main)
app.use(lazy)
app.route('/my-page', lazy(() => import('./views/my-page')))
// 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')
function main () {
return html`
<body class="Home">
<h1>home</h1>
<a href="/a">a</a><br>
<a href="/b">b</a>
</body>
`
}
module.exports = app.mount('body')
```
## API
The module exposes a [Nanocomponent][nanocomponent] class with two static
methods which are used for wrapping your views and `choo.mount`.
### `app.use(lazy)`
Hook up lazy view manager to the app. The lazy view store detects [jalla][jalla]
and [bankai][bankai] prefetch (_experimental_prefetch) behaviour so that server
side rendering works just as you'd expect.
### `LazyView.create(callback, loader?)`
### `lazy(callback, loader?)`
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.
when the view 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 a callback.
```javascript
// using promise
app.route('/my-page', LazyView.create(function () {
return fetchViewPromise()
}))
app.route('/my-page', lazy(() => import('./views/my-page')))
// using the callback
app.route('/another-page', LazyView.create(function (callback) {
fetchViewCallback(callback)
// using a callback
app.route('/another-page', lazy(function (callback) {
fetchView(function (err, view) {
callback(err, view)
})
}))

@@ -67,8 +51,7 @@ ```

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).
will be displayed while loading. By default, the node used to mount the app in
the DOM is used as loader (meaning the view remains unchanged while loading).
```javascript
app.route('/a', LazyView.create(
app.route('/a', lazy(
() => import('./my-view'),

@@ -79,61 +62,27 @@ (state, emit) => html`<body>Loading view…</body>`

### `LazyView.mount(app, selector)`
Wrapper function for `app.mount` which stores the selector internally to use as
fallback loader while fetching views.
During server side render, the store will expose the selector used by
`app.mount` on the app state and use that as the fallback loader view. If you
are not doing server side rendering and exposing the server side rendered state
as `initialState` on the client, a loader view is required. *Note: jalla does
this automatically for you.*
```diff
- module.exports = app.mount('body')
+ module.exports = LazyView.mount(app, 'body')
```
### Extending LazyView
You may extend on the LazyView component to add a shared framework wrapper, e.g.
a header and footer.
```javascript
// components/view/index.js
var html = require('choo/html')
var LazyView = require('choo-lazy-view')
var Header = require('../header')
var Footer = require('../footer')
module.exports = class View extends LazyView {
createElement (state, emit) {
return html`
<body>
${state.cache(Header, 'header').render()}
${super.createElement(state, emit)}
${state.cache(Footer, 'footer').render()}
</body>
`
}
}
```
```javascript
// index.js
var choo = require('choo')
var View = require('./components/view')
var app = choo()
app.route('/', View.create(() => import('./views/home')))
module.exports = View.mount(app, 'body')
```
### Events
Events are namespaced under `choo-lazy-view` and emitted when loading views.
Events are namespaced under `lazy-view` and emitted when loading views.
#### `choo-lazy-view:fetch`
When fetching a view.
#### `lazy-view:load(promise)`
When fetching a view. The argument `promise` resolves to the loaded view.
#### `choo-lazy-view:done`
When the view has been fetched and is about to rerender.
#### `lazy-view:success(view)`
When the view has been fetched, before the app will rerender. The argument
`view` is the resolved view.
#### `choo-lazy-view:error`
#### `lazy-view:error(err)`
When the view fails to load.
## License
MIT
[choo]: https://github.com/choojs/choo
[nanocomponent]: https://github.com/choojs/nanocomponent
[jalla]: https://github.com/jallajs/jalla
[bankai]: https://github.com/choojs/bankai
[split-require]: https://github.com/goto-bus-stop/split-require

@@ -140,0 +89,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc