diff --git a/.travis.yml b/.travis.yml
index ec71b5b5..a71ed287 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
node_js:
- '6'
-- '7'
- '8'
+- '10'
sudo: false
language: node_js
env:
diff --git a/README.md b/README.md
index d522096a..971b68c8 100644
--- a/README.md
+++ b/README.md
@@ -382,9 +382,9 @@ We use the `require('assert')` module from Node core to provide helpful error
messages in development. In production you probably want to strip this using
[unassertify][unassertify].
-To convert inlined HTML to valid DOM nodes we use `require('bel')`. This has
+To convert inlined HTML to valid DOM nodes we use `require('nanohtml')`. This has
overhead during runtime, so for production environments we should unwrap this
-using [yo-yoify][yo-yoify].
+using the [nanohtml transform][nanohtml].
Setting up browserify transforms can sometimes be a bit of hassle; to make this
more convenient we recommend using [bankai build][bankai] to build your assets for production.
@@ -414,9 +414,9 @@ answer short: we're using something even better.
### How can I support older browsers?
Template strings aren't supported in all browsers, and parsing them creates
significant overhead. To optimize we recommend running `browserify` with
-[yo-yoify][yo-yoify] as a global transform or using [bankai][bankai] directly.
+[nanohtml][nanohtml] as a global transform or using [bankai][bankai] directly.
```sh
-$ browserify -g yo-yoify
+$ browserify -g nanohtml
```
### Is choo production ready?
@@ -479,11 +479,11 @@ Render the application to a string. Useful for rendering on the server.
### `choo/html`
Create DOM nodes from template string literals. Exposes
-[bel](https://github.com/shama/bel). Can be optimized using
-[yo-yoify][yo-yoify].
+[nanohtml](https://github.com/choojs/nanohtml). Can be optimized using
+[nanohtml][nanohtml].
### `choo/html/raw`
-Exposes [bel/raw](https://github.com/shama/bel#unescaping) helper for rendering raw HTML content.
+Exposes [nanohtml/raw](https://github.com/shama/nanohtml#unescaping) helper for rendering raw HTML content.
## Installation
```sh
@@ -585,6 +585,7 @@ Become a backer, and buy us a coffee (or perhaps lunch?) every month or so.
[bankai]: https://github.com/choojs/bankai
[bel]: https://github.com/shama/bel
+[nanohtml]: https://github.com/choojs/nanohtml
[browserify]: https://github.com/substack/node-browserify
[budo]: https://github.com/mattdesl/budo
[es2020]: https://github.com/yoshuawuyts/es2020
@@ -594,6 +595,5 @@ Become a backer, and buy us a coffee (or perhaps lunch?) every month or so.
[nanomorph]: https://github.com/choojs/nanomorph
[nanorouter]: https://github.com/choojs/nanorouter
[yo-yo]: https://github.com/maxogden/yo-yo
-[yo-yoify]: https://github.com/shama/yo-yoify
[unassertify]: https://github.com/unassert-js/unassertify
[window-performance]: https://developer.mozilla.org/en-US/docs/Web/API/Performance
diff --git a/component/cache.js b/component/cache.js
new file mode 100644
index 00000000..101acc0d
--- /dev/null
+++ b/component/cache.js
@@ -0,0 +1,41 @@
+var assert = require('assert')
+var LRU = require('nanolru')
+
+module.exports = ChooComponentCache
+
+function ChooComponentCache (state, emit, lru) {
+ assert.ok(this instanceof ChooComponentCache, 'ChooComponentCache should be created with `new`')
+
+ assert.equal(typeof state, 'object', 'ChooComponentCache: state should be type object')
+ assert.equal(typeof emit, 'function', 'ChooComponentCache: emit should be type function')
+
+ if (typeof lru === 'number') this.cache = new LRU(lru)
+ else this.cache = lru || new LRU(100)
+ this.state = state
+ this.emit = emit
+}
+
+// Get & create component instances.
+ChooComponentCache.prototype.render = function (Component, id) {
+ assert.equal(typeof Component, 'function', 'ChooComponentCache.render: Component should be type function')
+ assert.ok(typeof id === 'string' || typeof id === 'number', 'ChooComponentCache.render: id should be type string or type number')
+
+ var el = this.cache.get(id)
+ if (!el) {
+ var args = []
+ for (var i = 2, len = arguments.length; i < len; i++) {
+ args.push(arguments[i])
+ }
+ args.unshift(Component, id, this.state, this.emit)
+ el = newCall.apply(newCall, args)
+ this.cache.set(id, el)
+ }
+
+ return el
+}
+
+// Because you can't call `new` and `.apply()` at the same time. This is a mad
+// hack, but hey it works so we gonna go for it. Whoop.
+function newCall (Cls) {
+ return new (Cls.bind.apply(Cls, arguments)) // eslint-disable-line
+}
diff --git a/component/index.js b/component/index.js
new file mode 100644
index 00000000..b639a1bf
--- /dev/null
+++ b/component/index.js
@@ -0,0 +1 @@
+module.exports = require('nanocomponent')
diff --git a/example/components/footer/clear-button.js b/example/components/footer/clear-button.js
new file mode 100644
index 00000000..ba632404
--- /dev/null
+++ b/example/components/footer/clear-button.js
@@ -0,0 +1,15 @@
+var html = require('bel')
+
+module.exports = deleteCompleted
+
+function deleteCompleted (emit) {
+ return html`
+
+ Clear completed
+
+ `
+
+ function deleteAllCompleted () {
+ emit('todos:deleteCompleted')
+ }
+}
diff --git a/example/components/footer/filter-button.js b/example/components/footer/filter-button.js
new file mode 100644
index 00000000..f37003b8
--- /dev/null
+++ b/example/components/footer/filter-button.js
@@ -0,0 +1,18 @@
+var html = require('bel')
+
+module.exports = filterButton
+
+function filterButton (name, filter, currentFilter, emit) {
+ var filterClass = filter === currentFilter
+ ? 'selected'
+ : ''
+
+ var uri = '#' + name.toLowerCase()
+ if (uri === '#all') uri = '/'
+
+ return html`
+
+ ${name}
+
+ `
+}
diff --git a/example/components/footer/index.js b/example/components/footer/index.js
new file mode 100644
index 00000000..3645a803
--- /dev/null
+++ b/example/components/footer/index.js
@@ -0,0 +1,50 @@
+var Component = require('../../../component')
+var html = require('bel')
+
+var clearButton = require('./clear-button')
+var filterButton = require('./filter-button')
+
+module.exports = class Footer extends Component {
+ constructor (name, state, emit) {
+ super(name)
+ this.state = state
+ this.emit = emit
+
+ this.local = this.state.components.footer = {}
+ this.setState()
+ }
+
+ setState () {
+ this.local.rawTodos = this.state.todos.clock
+ this.local.rawHref = this.state.href
+
+ this.local.filter = this.state.href.replace(/^\//, '') || ''
+ this.local.activeCount = this.state.todos.active.length
+ this.local.hasDone = this.state.todos.done.length || null
+ }
+
+ update () {
+ if (this.local.rawTodos !== this.state.todos.clock ||
+ this.local.rawHref !== this.state.href) {
+ this.setState()
+ return true
+ } else {
+ return false
+ }
+ }
+
+ createElement () {
+ return html``
+ }
+}
diff --git a/example/components/header.js b/example/components/header.js
new file mode 100644
index 00000000..ff682d4b
--- /dev/null
+++ b/example/components/header.js
@@ -0,0 +1,32 @@
+var Component = require('../../component')
+var html = require('bel')
+
+module.exports = class Header extends Component {
+ constructor (name, state, emit) {
+ super(name)
+ this.state = state
+ this.emit = emit
+ }
+
+ update () {
+ return false
+ }
+
+ createElement () {
+ return html``
+ }
+
+ createTodo (e) {
+ var value = e.target.value
+ if (e.keyCode === 13) {
+ e.target.value = ''
+ this.emit('todos:create', value)
+ }
+ }
+}
diff --git a/example/components/info.js b/example/components/info.js
new file mode 100644
index 00000000..f1b917cc
--- /dev/null
+++ b/example/components/info.js
@@ -0,0 +1,16 @@
+var Component = require('../../component')
+var html = require('bel')
+
+module.exports = class Info extends Component {
+ update () {
+ return false
+ }
+
+ createElement () {
+ return html``
+ }
+}
diff --git a/example/components/todos/index.js b/example/components/todos/index.js
new file mode 100644
index 00000000..7dbfd3a2
--- /dev/null
+++ b/example/components/todos/index.js
@@ -0,0 +1,65 @@
+var Component = require('../../../component')
+var html = require('bel')
+
+var Todo = require('./todo')
+
+module.exports = class Header extends Component {
+ constructor (name, state, emit) {
+ super(name)
+ this.state = state
+ this.emit = emit
+ this.local = this.state.components[name] = {}
+ this.setState()
+ }
+
+ setState () {
+ this.local.rawTodos = this.state.todos.clock
+ this.local.rawHref = this.state.href
+
+ this.local.allDone = this.state.todos.done.length === this.state.todos.all.length
+ this.local.filter = this.state.href.replace(/^\//, '') || ''
+ this.local.todos = this.local.filter === 'completed'
+ ? this.state.todos.done
+ : this.local.filter === 'active'
+ ? this.state.todos.active
+ : this.state.todos.all
+ }
+
+ update () {
+ if (this.local.rawTodos !== this.state.todos.clock ||
+ this.local.rawHref !== this.state.href) {
+ this.setState()
+ return true
+ } else {
+ return false
+ }
+ }
+
+ createElement () {
+ return html``
+ }
+
+ createTodo (e) {
+ var value = e.target.value
+ if (e.keyCode === 13) {
+ e.target.value = ''
+ this.emit('todos:create', value)
+ }
+ }
+
+ toggleAll () {
+ this.emit('todos:toggleAll')
+ }
+}
diff --git a/example/components/todos/todo.js b/example/components/todos/todo.js
new file mode 100644
index 00000000..231e3acb
--- /dev/null
+++ b/example/components/todos/todo.js
@@ -0,0 +1,64 @@
+var html = require('bel')
+
+module.exports = Todo
+
+function Todo (todo, emit) {
+ var clx = classList({ completed: todo.done, editing: todo.editing })
+ return html`
+
+
+
+ ${todo.name}
+
+
+
+
+ `
+
+ function toggle (e) {
+ emit('todos:toggle', todo.id)
+ }
+
+ function edit (e) {
+ emit('todos:edit', todo.id)
+ }
+
+ function destroy (e) {
+ emit('todos:delete', todo.id)
+ }
+
+ function update (e) {
+ emit('todos:update', {
+ id: todo.id,
+ editing: false,
+ name: e.target.value
+ })
+ }
+
+ function handleEditKeydown (e) {
+ if (e.keyCode === 13) update(e) // Enter
+ else if (e.code === 27) emit('todos:unedit') // Escape
+ }
+
+ function classList (classes) {
+ var str = ''
+ var keys = Object.keys(classes)
+ for (var i = 0, len = keys.length; i < len; i++) {
+ var key = keys[i]
+ var val = classes[key]
+ if (val) str += (key + ' ')
+ }
+ return str
+ }
+}
diff --git a/example/index.js b/example/index.js
index 5c767b15..117d05e3 100644
--- a/example/index.js
+++ b/example/index.js
@@ -8,11 +8,11 @@ var app = choo()
if (process.env.NODE_ENV !== 'production') {
app.use(require('choo-devtools')())
}
-app.use(require('./store'))
+app.use(require('./stores/todos'))
-app.route('/', require('./view'))
-app.route('#active', require('./view'))
-app.route('#completed', require('./view'))
-app.route('*', require('./view'))
+app.route('/', require('./views/main'))
+app.route('#active', require('./views/main'))
+app.route('#completed', require('./views/main'))
+app.route('*', require('./views/main'))
module.exports = app.mount('body')
diff --git a/example/store.js b/example/stores/todos.js
similarity index 83%
rename from example/store.js
rename to example/stores/todos.js
index 63f206d6..d6e2efa3 100644
--- a/example/store.js
+++ b/example/stores/todos.js
@@ -1,30 +1,18 @@
module.exports = todoStore
function todoStore (state, emitter) {
- if (!state.todos) {
- state.todos = {}
-
- state.todos.active = []
- state.todos.done = []
- state.todos.all = []
-
- state.todos.idCounter = 0
+ state.todos = {
+ clock: 0,
+ idCounter: 0,
+ active: [],
+ done: [],
+ all: []
}
- // Always reset when application boots
- state.todos.input = ''
-
- // Register emitters after DOM is loaded to speed up DOM loading
emitter.on('DOMContentLoaded', function () {
- // CRUD
emitter.on('todos:create', create)
emitter.on('todos:update', update)
emitter.on('todos:delete', del)
-
- // Special
- emitter.on('todos:input', oninput)
-
- // Shorthand
emitter.on('todos:edit', edit)
emitter.on('todos:unedit', unedit)
emitter.on('todos:toggle', toggle)
@@ -32,10 +20,6 @@ function todoStore (state, emitter) {
emitter.on('todos:deleteCompleted', deleteCompleted)
})
- function oninput (text) {
- state.todos.input = text
- }
-
function create (name) {
var item = {
id: state.todos.idCounter,
@@ -47,21 +31,21 @@ function todoStore (state, emitter) {
state.todos.idCounter += 1
state.todos.active.push(item)
state.todos.all.push(item)
- emitter.emit('render')
+ render()
}
function edit (id) {
state.todos.all.forEach(function (todo) {
if (todo.id === id) todo.editing = true
})
- emitter.emit('render')
+ render()
}
function unedit (id) {
state.todos.all.forEach(function (todo) {
if (todo.id === id) todo.editing = false
})
- emitter.emit('render')
+ render()
}
function update (newTodo) {
@@ -78,7 +62,7 @@ function todoStore (state, emitter) {
}
Object.assign(todo, newTodo)
- emitter.emit('render')
+ render()
}
function del (id) {
@@ -111,7 +95,7 @@ function todoStore (state, emitter) {
})
active.splice(activeIndex, 1)
}
- emitter.emit('render')
+ render()
}
function deleteCompleted (data) {
@@ -121,7 +105,7 @@ function todoStore (state, emitter) {
state.todos.all.splice(index, 1)
})
state.todos.done = []
- emitter.emit('render')
+ render()
}
function toggle (id) {
@@ -135,7 +119,7 @@ function todoStore (state, emitter) {
var index = arr.indexOf(todo)
arr.splice(index, 1)
target.push(todo)
- emitter.emit('render')
+ render()
}
function toggleAll (data) {
@@ -155,6 +139,11 @@ function todoStore (state, emitter) {
state.todos.active = []
}
+ render()
+ }
+
+ function render () {
+ state.todos.clock += 1
emitter.emit('render')
}
}
diff --git a/example/test.js b/example/test.js
index 116e220f..e7cef737 100644
--- a/example/test.js
+++ b/example/test.js
@@ -2,7 +2,7 @@ var EventEmitter = require('events').EventEmitter
var spok = require('spok')
var tape = require('tape')
-var todoStore = require('./store')
+var todoStore = require('./stores/todos')
tape('should initialize empty state', function (t) {
var emitter = new EventEmitter()
@@ -19,25 +19,6 @@ tape('should initialize empty state', function (t) {
t.end()
})
-tape('restore previous state', function (t) {
- var emitter = new EventEmitter()
- var state = {
- todos: {
- idCounter: 100,
- active: [],
- done: [],
- all: []
- }
- }
- todoStore(state, emitter)
- spok(t, state, {
- todos: {
- idCounter: 100
- }
- })
- t.end()
-})
-
tape('todos:create', function (t) {
var emitter = new EventEmitter()
var state = {}
diff --git a/example/view.js b/example/view.js
deleted file mode 100644
index 9f120b55..00000000
--- a/example/view.js
+++ /dev/null
@@ -1,190 +0,0 @@
-var html = require('bel') // cannot require choo/html because it's a nested repo
-
-module.exports = mainView
-
-function mainView (state, emit) {
- emit('log:debug', 'Rendering main view')
- return html`
-
-
- ${Header(state, emit)}
- ${TodoList(state, emit)}
- ${Footer(state, emit)}
-
-
-
- `
-}
-
-function Header (state, emit) {
- return html`
-
- `
-
- function createTodo (e) {
- var value = e.target.value
- if (!value) return
- if (e.keyCode === 13) {
- emit('todos:input', '')
- emit('todos:create', value)
- } else {
- emit('todos:input', value)
- }
- }
-}
-
-function Footer (state, emit) {
- var filter = state.href.replace(/^\//, '') || ''
- var activeCount = state.todos.active.length
- var hasDone = state.todos.done.length
-
- return html`
-
- `
-
- function filterButton (name, filter, currentFilter, emit) {
- var filterClass = filter === currentFilter
- ? 'selected'
- : ''
-
- var uri = '#' + name.toLowerCase()
- if (uri === '#all') uri = '/'
- return html`
-
-
- ${name}
-
-
- `
- }
-
- function deleteCompleted (emit) {
- return html`
-
- Clear completed
-
- `
-
- function deleteAllCompleted () {
- emit('todos:deleteCompleted')
- }
- }
-}
-
-function TodoItem (todo, emit) {
- var clx = classList({ completed: todo.done, editing: todo.editing })
- return html`
-
-
-
- ${todo.name}
-
-
-
-
- `
-
- function toggle (e) {
- emit('todos:toggle', todo.id)
- }
-
- function edit (e) {
- emit('todos:edit', todo.id)
- }
-
- function destroy (e) {
- emit('todos:delete', todo.id)
- }
-
- function update (e) {
- emit('todos:update', {
- id: todo.id,
- editing: false,
- name: e.target.value
- })
- }
-
- function handleEditKeydown (e) {
- if (e.keyCode === 13) update(e) // Enter
- else if (e.code === 27) emit('todos:unedit') // Escape
- }
-
- function classList (classes) {
- var str = ''
- var keys = Object.keys(classes)
- for (var i = 0, len = keys.length; i < len; i++) {
- var key = keys[i]
- var val = classes[key]
- if (val) str += (key + ' ')
- }
- return str
- }
-}
-
-function TodoList (state, emit) {
- var filter = state.href.replace(/^\//, '') || ''
- var items = filter === 'completed'
- ? state.todos.done
- : filter === 'active'
- ? state.todos.active
- : state.todos.all
-
- var allDone = state.todos.done.length === state.todos.all.length
-
- var nodes = items.map(function (todo) {
- return TodoItem(todo, emit)
- })
-
- return html`
-
- `
-
- function toggleAll () {
- emit('todos:toggleAll')
- }
-}
diff --git a/example/views/main.js b/example/views/main.js
new file mode 100644
index 00000000..67d74547
--- /dev/null
+++ b/example/views/main.js
@@ -0,0 +1,21 @@
+var html = require('bel') // cannot require choo/html because it's a nested repo
+
+var Header = require('../components/header')
+var Footer = require('../components/footer')
+var Todos = require('../components/todos')
+var Info = require('../components/info')
+
+module.exports = mainView
+
+function mainView (state, emit) {
+ return html`
+
+
+ ${state.cache(Header, 'header').render()}
+ ${state.cache(Todos, 'todos').render()}
+ ${state.cache(Footer, 'footer').render()}
+
+ ${state.cache(Info, 'info').render()}
+
+ `
+}
diff --git a/html/index.d.ts b/html/index.d.ts
index fd11f050..03f50424 100644
--- a/html/index.d.ts
+++ b/html/index.d.ts
@@ -1,2 +1,2 @@
-import * as bel from "bel"
-export = bel
+import * as nanohtml from "nanohtml"
+export = nanohtml
diff --git a/html/index.js b/html/index.js
index e25543b4..95dfe601 100644
--- a/html/index.js
+++ b/html/index.js
@@ -1 +1 @@
-module.exports = require('bel')
+module.exports = require('nanohtml')
diff --git a/html/raw.js b/html/raw.js
index 975455ce..5de5b80c 100644
--- a/html/raw.js
+++ b/html/raw.js
@@ -1 +1 @@
-module.exports = require('bel/raw')
+module.exports = require('nanohtml/raw')
diff --git a/index.d.ts b/index.d.ts
index 0563609b..27280d32 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -6,7 +6,7 @@ export = Choo
declare class Choo {
constructor (opts?: Choo.IChoo)
- use (callback: (state: Choo.IState, emitter: EventEmitter) => void): void
+ use (callback: (state: Choo.IState, emitter: EventEmitter, app: this) => void): void
route (routeName: string, handler: (state: Choo.IState, emit: (name: string, ...args: any[]) => void) => void): void
mount (selector: string): void
start (): HTMLElement
diff --git a/index.js b/index.js
index 8326baf1..17d70bd3 100644
--- a/index.js
+++ b/index.js
@@ -11,6 +11,8 @@ var nanobus = require('nanobus')
var assert = require('assert')
var xtend = require('xtend')
+var Cache = require('./component/cache')
+
module.exports = Choo
var HISTORY_OBJECT = {}
@@ -39,25 +41,30 @@ function Choo (opts) {
this._hrefEnabled = opts.href === undefined ? true : opts.href
this._hasWindow = typeof window !== 'undefined'
this._createLocation = nanolocation
+ this._cache = opts.cache
this._loaded = false
this._stores = [ondomtitlechange]
this._tree = null
- // properties that are part of the API
- this.router = nanorouter()
- this.emitter = nanobus('choo.emit')
- this.emit = this.emitter.emit.bind(this.emitter)
-
- var events = { events: this._events }
+ // state
+ var _state = {
+ events: this._events,
+ components: {}
+ }
if (this._hasWindow) {
this.state = window.initialState
- ? xtend(window.initialState, events)
- : events
+ ? xtend(window.initialState, _state)
+ : _state
delete window.initialState
} else {
- this.state = events
+ this.state = _state
}
+ // properties that are part of the API
+ this.router = nanorouter({ curry: true })
+ this.emitter = nanobus('choo.emit')
+ this.emit = this.emitter.emit.bind(this.emitter)
+
// listen for title changes; available even when calling .toString()
if (this._hasWindow) this.state.title = document.title
function ondomtitlechange (state) {
@@ -130,6 +137,7 @@ Choo.prototype.start = function () {
}
}
+ this._setCache(this.state)
this._stores.forEach(function (initStore) {
initStore(self.state)
})
@@ -203,6 +211,7 @@ Choo.prototype.toString = function (location, state) {
assert.equal(typeof location, 'string', 'choo.toString: location should be type string')
assert.equal(typeof state, 'object', 'choo.toString: state should be type object')
+ this._setCache(this.state)
this.emitter.removeAllListeners()
this._stores.forEach(function (initStore) {
initStore(state)
@@ -238,3 +247,23 @@ Choo.prototype._prerender = function (state) {
routeTiming()
return res
}
+
+Choo.prototype._setCache = function (state) {
+ var cache = new Cache(state, this.emitter.emit.bind(this.emitter), this._cache)
+ state.cache = renderComponent
+
+ function renderComponent (Component, id) {
+ assert.equal(typeof Component, 'function', 'choo.state.cache: Component should be type function')
+ var args = []
+ for (var i = 0, len = arguments.length; i < len; i++) {
+ args.push(arguments[i])
+ }
+ return cache.render.apply(cache, args)
+ }
+
+ // When the state gets stringified, make sure `state.cache` isn't
+ // stringified too.
+ renderComponent.toJSON = function () {
+ return null
+ }
+}
diff --git a/package.json b/package.json
index 1c7cd430..09e1ff19 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "choo",
- "version": "6.10.3",
+ "version": "6.12.1",
"description": "A 4kb framework for creating sturdy frontend applications",
"main": "index.js",
"files": [
@@ -9,12 +9,17 @@
"html/index.js",
"html/raw.js",
"html/index.d.ts",
+ "component/cache.js",
+ "component/index.js",
"dist",
"example"
],
+ "browser": {
+ "assert": "nanoassert"
+ },
"scripts": {
- "build": "mkdir -p dist/ && browserify index -p bundle-collapser/plugin > dist/bundle.js && browserify index -p tinyify > dist/bundle.min.js && cat dist/bundle.min.js | gzip --best --stdout | wc -c | pretty-bytes",
- "deps": "dependency-check --entry ./html/index.js . && dependency-check . --extra --no-dev --entry ./html/index.js",
+ "build": "mkdir -p dist/ && browserify index -s Choo -p bundle-collapser/plugin > dist/bundle.js && browserify index -s Choo -p tinyify > dist/bundle.min.js && cat dist/bundle.min.js | gzip --best --stdout | wc -c | pretty-bytes",
+ "deps": "dependency-check --entry ./html/index.js . && dependency-check . --extra --no-dev --entry ./html/index.js --entry ./component/index.js -i nanoassert",
"inspect": "browserify --full-paths index -g unassertify -g uglifyify | discify --open",
"prepublishOnly": "npm run build",
"start": "bankai start example",
@@ -31,11 +36,14 @@
],
"license": "MIT",
"dependencies": {
- "bel": "^5.1.3",
"document-ready": "^2.0.1",
+ "nanoassert": "^1.1.0",
"nanobus": "^4.2.0",
+ "nanocomponent": "^6.5.0",
"nanohref": "^3.0.0",
+ "nanohtml": "^1.1.0",
"nanolocation": "^1.0.0",
+ "nanolru": "^1.0.0",
"nanomorph": "^5.1.2",
"nanoquery": "^1.1.0",
"nanoraf": "^3.0.0",
@@ -45,19 +53,19 @@
"xtend": "^4.0.1"
},
"devDependencies": {
- "@types/node": "^8.0.20",
- "browserify": "^14.3.0",
+ "@types/node": "^10.3.1",
+ "browserify": "^16.2.2",
"bundle-collapser": "^1.2.1",
- "dependency-check": "^2.8.0",
+ "dependency-check": "^3.1.0",
"discify": "^1.6.0",
"hyperscript": "^2.0.2",
"pretty-bytes-cli": "^2.0.0",
- "spok": "^0.8.1",
- "standard": "^10.0.0",
+ "spok": "^0.9.1",
+ "standard": "^11.0.1",
"tape": "^4.6.3",
"tinyify": "^2.2.0",
"uglify-es": "^3.0.17",
- "uglifyify": "^4.0.1",
+ "uglifyify": "^5.0.0",
"unassertify": "^2.0.4"
}
}
diff --git a/test.js b/test.js
index 1fde5e7a..afc97ee4 100644
--- a/test.js
+++ b/test.js
@@ -63,3 +63,19 @@ tape('should not leak state on render', function (t) {
return html`Hello ${state.route}`
}
})
+
+tape('should expose a public API', function (t) {
+ var app = choo()
+
+ t.equal(typeof app.route, 'function', 'app.route prototype method exists')
+ t.equal(typeof app.toString, 'function', 'app.toString prototype method exists')
+ t.equal(typeof app.start, 'function', 'app.start prototype method exists')
+ t.equal(typeof app.mount, 'function', 'app.mount prototype method exists')
+ t.equal(typeof app.emitter, 'object', 'app.emitter prototype method exists')
+
+ t.equal(typeof app.emit, 'function', 'app.emit instance method exists')
+ t.equal(typeof app.router, 'object', 'app.router instance object exists')
+ t.equal(typeof app.state, 'object', 'app.state instance object exists')
+
+ t.end()
+})