v6 beta branch (#489)
* become prototype based upgrade to new nanobus remove nanohistory add nanotiming remove nanomount move newTree to next tick upgrade timing API add more node warnings to .start/.mount add morph timing pass app instance to .use() self-clearing async-timing clean up timings better mount error fix mount bug de-prototype helper functions update to latest nanotiming upgrade to nanotiming 5 update nanotiming add toString asserts more assertions add event based tracing expose createlocation assert return types from render to always be the same add navigate event expose route on state expose events update uglify use scroll-to-anchor update nanobus document events update docs more docs changelog v6 upgrade nanomorph fixup! neatify morph assertions update bel dep add popstate docs to changelog * expose events on state * upgrade deps
This commit is contained in:
@@ -1,3 +1,35 @@
|
||||
## `6.0.0` Same as it ever was
|
||||
In the past few months we've been able to use `choo@5` a bunch, and people seem
|
||||
to like it a lot! In this patch all we're doing is taking choo's existing API,
|
||||
and polishing the internals. In theory this means breaking changes, but in
|
||||
practice it will mostly mean people need to update their dependencies, and
|
||||
things will work great.
|
||||
|
||||
Choo v6 includes the upgrades to `bel@5` and `nanomorph@5`. This means up to
|
||||
20x faster server rendering, and up to 10x improved browser rendering speeds.
|
||||
We've also fixed DOM node caching, and introduced sibling node reordering.
|
||||
|
||||
This release also includes an overhauled timing API. We're now capturing more
|
||||
events, and are leveraging this in tools like `choo-log` to provide consistent
|
||||
feedback on performance.
|
||||
|
||||
Choo is now also completely prototype based. It not only means faster execution
|
||||
times, and more maintainable codebase - but you can also override methods if
|
||||
you ever need to.
|
||||
|
||||
We've also tweaked the event system a little. All built-in event names are now
|
||||
available as constants under `app.state.events`. And we've introduced three new
|
||||
events: `'navigate'` will trigger whenever a route changes, `'replaceState'`
|
||||
can be called to redirect routes, and `popState` which is emitted when the back
|
||||
button in the browser is pressed.
|
||||
|
||||
And that's about it - we've upgraded a whole slew of deps, and removed a few we
|
||||
didn't quite use. Overall we're quite proud of the new codebase, and filled
|
||||
with joy we didn't have to make any changes to the API - additions only.
|
||||
|
||||
Thanks heaps for reading this far, we hope you enjoy this release as much as we
|
||||
did building it. Happy coding! -Team Choo :sparkles:
|
||||
|
||||
## `5.1.0` Timing API support
|
||||
In order to improve, we must measure first. Specifically when it comes to
|
||||
framerate there are very specific numbers we can rely on: `~16ms` for any given
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
- [Features](#features)
|
||||
- [Example](#example)
|
||||
- [Philosophy](#philosophy)
|
||||
- [Events](#events)
|
||||
- [Server Rendering](#server-rendering)
|
||||
- [Optimizations](#optimizations)
|
||||
- [FAQ](#faq)
|
||||
- [API](#api)
|
||||
@@ -103,10 +105,11 @@
|
||||
## Example
|
||||
```js
|
||||
var html = require('choo/html')
|
||||
var log = require('choo-log')
|
||||
var choo = require('choo')
|
||||
|
||||
var app = choo()
|
||||
app.use(logger)
|
||||
app.use(log())
|
||||
app.use(countStore)
|
||||
app.route('/', mainView)
|
||||
app.mount('body')
|
||||
@@ -124,12 +127,6 @@ function mainView (state, emit) {
|
||||
}
|
||||
}
|
||||
|
||||
function logger (state, emitter) {
|
||||
emitter.on('*', function (messageName, data) {
|
||||
console.log('event', messageName, data)
|
||||
})
|
||||
}
|
||||
|
||||
function countStore (state, emitter) {
|
||||
state.count = 0
|
||||
emitter.on('increment', function (count) {
|
||||
@@ -161,14 +158,99 @@ out. And once an application is built, we want it to be small, performant and
|
||||
easy to reason about. All of which makes for easy to debug code, better results
|
||||
and super smiley faces.
|
||||
|
||||
## Events
|
||||
At the core of Choo is an event emitter, which is used for both application
|
||||
logic but also to interface with the framework itself. The package we use for
|
||||
this is [nanobus](https://github.com/yoshuawuyts/nanobus).
|
||||
|
||||
You can access the emitter through `app.use(state, emitter)`, `app.route(route,
|
||||
view(state, emit))` or `app.emitter`. Routes only have access to the
|
||||
`emitter.emit` method to encourage people to separate business logic from
|
||||
render logic.
|
||||
|
||||
The purpose of the emitter is two-fold: it allows wiring up application code
|
||||
together, and splitting it off nicely - but it also allows communicating with
|
||||
the Choo framework itself. All events can be read as constants from
|
||||
`state.events`. Choo ships with the following events built in:
|
||||
|
||||
### `'DOMContentLoaded'`|`state.events.DOMCONTENTLOADED`
|
||||
Choo emits this when the DOM is ready. Similar to the DOM's
|
||||
`'DOMContentLoaded'` event, except it will be emitted even if the listener is
|
||||
added _after_ the DOM became ready. Uses
|
||||
[document-ready](https://github.com/bendrucker/document-ready) under the hood.
|
||||
|
||||
### `'render'`|`state.events.RENDER`
|
||||
This event should be emitted to re-render the DOM. A common pattern is to
|
||||
update the `state` object, and then emit the `'render'` event straight after.
|
||||
Note that `'render'` will only have an effect once the `DOMContentLoaded` event
|
||||
has been fired.
|
||||
|
||||
### `'navigate'`|`state.events.NAVIGATE`
|
||||
Choo emits this event whenever routes change. This is triggered by either
|
||||
`'pushState'`, `'replaceState'` or `'popState'`.
|
||||
|
||||
### `'pushState'`|`state.events.PUSHSTATE`
|
||||
This event should be emitted to navigate to a new route. The new route is added
|
||||
to the browser's history stack, and will emit `'navigate'` and `'render'`.
|
||||
Similar to
|
||||
[history.pushState](http://devdocs.io/dom/history_api).
|
||||
|
||||
### `'replaceState'`|`state.events.REPLACESTATE`
|
||||
This event should be emitted to navigate to a new route. The new route replaces
|
||||
the current entry in the browser's history stack, and will emit `'navigate'`
|
||||
and `'render'`. Similar to
|
||||
[history.replaceState](http://devdocs.io/dom/history#history-replacestate).
|
||||
|
||||
### `'popState'`|`state.events.POPSTATE`
|
||||
This event should be emitted to navigate to a previous route. The new route
|
||||
will be a previous entry in the browser's history stack, and will emit
|
||||
`'navigate'` and `'render'`. Similar to
|
||||
[history.popState](http://devdocs.io/dom_events/popstate).
|
||||
|
||||
## State
|
||||
Choo comes with a shared state object. This object can be mutated freely, and
|
||||
is passed into the view functions whenever `'render'` is emitted. The state
|
||||
object comes with a few properties set.
|
||||
|
||||
### `state.events`
|
||||
A mapping of Choo's built in events. It's recommended to extend this object
|
||||
with your application's events. By defining your event names once and setting
|
||||
them on `state.events`, it reduces the chance of typos, generally autocompletes
|
||||
better, makes refactoring easier and compresses better.
|
||||
|
||||
### `state.params`
|
||||
The current params taken from the route. E.g. `/foo/:bar` becomes available as
|
||||
`state.params.bar` If a wildcard route is used (`/foo/*`) it's available as
|
||||
`state.params.wildcard`.
|
||||
|
||||
### `state.route`
|
||||
The current name of the route used in the router (e.g. `/foo/:bar`).
|
||||
|
||||
## Server Rendering
|
||||
Choo was built with Node in mind. To render on the server call `.toString()` on
|
||||
your application.
|
||||
|
||||
```js
|
||||
var html = require('choo/html')
|
||||
var choo = require('choo')
|
||||
|
||||
var app = choo()
|
||||
app.route('/', function (state, emit) {
|
||||
return html`<div>Hello ${state.name}</div>`
|
||||
})
|
||||
|
||||
var state = { name: 'Node' }
|
||||
var string = app.toString('/', state)
|
||||
|
||||
console.log(string)
|
||||
// => '<div>Hello Node</div>'
|
||||
```
|
||||
|
||||
## Optimizations
|
||||
Choo is reasonably fast out of the box. But sometimes you might hit a scenario
|
||||
where a particular part of the UI slows down the application, and you want to
|
||||
speed it up. Here are some optimizations that are possible.
|
||||
|
||||
### Reordering lists
|
||||
To be implemented. (See [yoshuawuyts/nanomorph#8](https://github.com/yoshuawuyts/nanomorph/issues/8))
|
||||
|
||||
### Caching DOM elements
|
||||
Sometimes we want to tell the algorithm to not evaluate certain nodes (and its
|
||||
children). This can be because we're sure they haven't changed, or perhaps
|
||||
@@ -185,6 +267,22 @@ el.isSameNode = function (target) {
|
||||
}
|
||||
```
|
||||
|
||||
### Reordering lists
|
||||
It's common to work with lists of elements on the DOM. Adding, removing or
|
||||
reordering elements in a list can be rather expensive. To optimize this you can
|
||||
add an `id` attribute to a DOM node. When reordering nodes it will compare
|
||||
nodes with the same ID against each other, resulting in far fewer re-renders.
|
||||
This is especially potent when coupled with DOM node caching.
|
||||
|
||||
```js
|
||||
var el = html`
|
||||
<section>
|
||||
<div id="first">hello</div>
|
||||
<div id="second">world</div>
|
||||
</section>
|
||||
`
|
||||
```
|
||||
|
||||
### Pruning dependencies
|
||||
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
|
||||
@@ -243,28 +341,14 @@ Initialize a new `choo` instance. `opts` can also contain the following values:
|
||||
history API.
|
||||
- __opts.href:__ default: `true`. Handle all relative `<a
|
||||
href="<location>"></a>` clicks and call `emit('render')`
|
||||
- __opts.timing:__ default: `true`. Enables calls to the
|
||||
[window.performance][window-performance] timing API. Timing calls will not
|
||||
run in browsers that don't support it out of the box. The timing marks are
|
||||
`choo:renderStart`, `choo:renderEnd`. The resulting diff is stored as
|
||||
`choo:render`.
|
||||
|
||||
### `app.use(callback(state, emitter))`
|
||||
Call a function and pass it a `state` and `emitter`. `emitter` is an instance
|
||||
of [nanobus](https://github.com/yoshuawuyts/nanobus/). You can listen to
|
||||
messages by calling `emitter.on()` and emit messages by calling `emitter.emit()`.
|
||||
messages by calling `emitter.on()` and emit messages by calling
|
||||
`emitter.emit()`.
|
||||
|
||||
Choo fires messages when certain events happen:
|
||||
- __`.on('DOMContentLoaded')`__: when the DOM has succesfully finished loading
|
||||
- __`.on('render')`__: when the DOM re-renders
|
||||
- __`.on('pushState')`__: when the history API is triggered
|
||||
|
||||
The `render` event should be emitted (`emitter.emit('render')`) whenever you want the app to re-render the DOM - it won't happen on its own except when you navigate between routes.
|
||||
|
||||
The `pushState` can be emitted to navigate between routes: `emitter.emit('pushState', '/some/route')`.
|
||||
You can emit `replaceState` which will overwrite the current entry in the browser history, but be very careful as this removes the option of navigating back!
|
||||
|
||||
Note `render` will only have an effect once the `DOMContentLoaded` event has been fired.
|
||||
See [#events](#events) for an overview of all events.
|
||||
|
||||
### `app.route(routeName, handler)`
|
||||
Register a route on the router. Uses [nanorouter][nanorouter] under the hood.
|
||||
@@ -281,7 +365,8 @@ anchor links on the page is generally not recommended.
|
||||
New routes can be triggered through `emitter.emit('pushState', <routename>)`.
|
||||
By default we also catch and match all `<a href="">` clicks against the router.
|
||||
This can be disabled by setting `opts.href` to `false` in the constructor.
|
||||
Routing via `pushState` will not work until the `DOMContentLoaded` event has been fired.
|
||||
Routing via `pushState` will not work until the `DOMContentLoaded` event has
|
||||
been fired.
|
||||
|
||||
If you need choo to ignore a particular route, you can add `data-no-routing`
|
||||
attribute with `<a href="" data-no-routing>`. This is especially useful for
|
||||
|
||||
@@ -65,8 +65,6 @@ function todoStore (state, emitter) {
|
||||
|
||||
// Register emitters after DOM is loaded to speed up DOM loading
|
||||
emitter.on('DOMContentLoaded', function () {
|
||||
emitter.emit('log:debug', 'Loading todos model')
|
||||
|
||||
// CRUD
|
||||
emitter.on('todos:create', create)
|
||||
emitter.on('todos:update', update)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var scrollToAnchor = require('scroll-to-anchor')
|
||||
var documentReady = require('document-ready')
|
||||
var nanohistory = require('nanohistory')
|
||||
var nanotiming = require('nanotiming')
|
||||
var nanorouter = require('nanorouter')
|
||||
var nanomount = require('nanomount')
|
||||
var nanomorph = require('nanomorph')
|
||||
var nanohref = require('nanohref')
|
||||
var nanoraf = require('nanoraf')
|
||||
@@ -10,128 +10,171 @@ var assert = require('assert')
|
||||
|
||||
module.exports = Choo
|
||||
|
||||
var HISTORY_OBJECT = {}
|
||||
|
||||
function Choo (opts) {
|
||||
if (!(this instanceof Choo)) return new Choo(opts)
|
||||
opts = opts || {}
|
||||
|
||||
assert.equal(typeof opts, 'object', 'choo: opts should be type object')
|
||||
|
||||
var routerOpts = {
|
||||
default: opts.defaultRoute || '/404',
|
||||
curry: true
|
||||
}
|
||||
|
||||
var timingEnabled = opts.timing === undefined ? true : opts.timing
|
||||
var hasWindow = typeof window !== 'undefined'
|
||||
var hasPerformance = hasWindow && window.performance && window.performance.mark
|
||||
var router = nanorouter(routerOpts)
|
||||
var bus = nanobus()
|
||||
var rerender = null
|
||||
var tree = null
|
||||
var state = {}
|
||||
|
||||
return {
|
||||
toString: toString,
|
||||
use: register,
|
||||
mount: mount,
|
||||
router: router,
|
||||
route: route,
|
||||
start: start
|
||||
// define events used by choo
|
||||
this._events = {
|
||||
DOMCONTENTLOADED: 'DOMContentLoaded',
|
||||
REPLACESTATE: 'replaceState',
|
||||
PUSHSTATE: 'pushState',
|
||||
NAVIGATE: 'navigate',
|
||||
POPSTATE: 'popState',
|
||||
RENDER: 'render'
|
||||
}
|
||||
|
||||
function route (route, handler) {
|
||||
router.on(route, function (params) {
|
||||
// properties for internal use only
|
||||
this._historyEnabled = opts.history === undefined ? true : opts.history
|
||||
this._hrefEnabled = opts.href === undefined ? true : opts.href
|
||||
this._tree = null
|
||||
|
||||
// properties that are part of the API
|
||||
this.router = nanorouter(routerOpts)
|
||||
this.emitter = nanobus('choo.emit')
|
||||
this.state = { events: this._events }
|
||||
}
|
||||
|
||||
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')
|
||||
|
||||
var self = this
|
||||
this.router.on(route, function (params) {
|
||||
return function () {
|
||||
state.params = params
|
||||
return handler(state, emit)
|
||||
self.state.params = params
|
||||
self.state.route = route
|
||||
var routeTiming = nanotiming("choo.route('" + route + "')")
|
||||
var res = handler(self.state, function (eventName, data) {
|
||||
self.emitter.emit(eventName, data)
|
||||
})
|
||||
routeTiming()
|
||||
return res
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function register (cb) {
|
||||
cb(state, bus)
|
||||
}
|
||||
Choo.prototype.use = function (cb) {
|
||||
assert.equal(typeof cb, 'function', 'choo.use: cb should be type function')
|
||||
var endTiming = nanotiming('choo.use')
|
||||
cb(this.state, this.emitter, this)
|
||||
endTiming()
|
||||
}
|
||||
|
||||
function start () {
|
||||
if (opts.history !== false) {
|
||||
nanohistory(function (href) {
|
||||
bus.emit('pushState')
|
||||
Choo.prototype.start = function () {
|
||||
assert.equal(typeof window, 'object', 'choo.start: window was not found. .start() must be called in a browser, use .toString() if running in Node')
|
||||
|
||||
var self = this
|
||||
|
||||
if (this._historyEnabled) {
|
||||
this.emitter.prependListener(this._events.NAVIGATE, function () {
|
||||
self.emitter.emit(self._events.RENDER)
|
||||
setTimeout(scrollToAnchor.bind(null, window.location.hash), 0)
|
||||
})
|
||||
|
||||
bus.prependListener('pushState', updateHistory.bind(null, 'push'))
|
||||
bus.prependListener('replaceState', updateHistory.bind(null, 'replace'))
|
||||
this.emitter.prependListener(this._events.POPSTATE, function () {
|
||||
self.emitter.emit(self._events.NAVIGATE)
|
||||
})
|
||||
|
||||
if (opts.href !== false) {
|
||||
this.emitter.prependListener(this._events.PUSHSTATE, function (href) {
|
||||
assert.equal(typeof href, 'string', 'events.pushState: href should be type string')
|
||||
window.history.pushState(HISTORY_OBJECT, null, href)
|
||||
self.emitter.emit(self._events.NAVIGATE)
|
||||
})
|
||||
|
||||
this.emitter.prependListener(this._events.REPLACESTATE, function (href) {
|
||||
assert.equal(typeof href, 'string', 'events.replaceState: href should be type string')
|
||||
window.history.replaceState(HISTORY_OBJECT, null, href)
|
||||
self.emitter.emit(self._events.NAVIGATE)
|
||||
})
|
||||
|
||||
window.onpopstate = function () {
|
||||
self.emitter.emit(self._events.POPSTATE)
|
||||
}
|
||||
|
||||
if (self._hrefEnabled) {
|
||||
nanohref(function (location) {
|
||||
var href = location.href
|
||||
var currHref = window.location.href
|
||||
if (href === currHref) return
|
||||
bus.emit('pushState', href)
|
||||
self.emitter.emit(self._events.PUSHSTATE, href)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function updateHistory (mode, href) {
|
||||
if (href) window.history[mode + 'State']({}, null, href)
|
||||
bus.emit('render')
|
||||
setTimeout(function () {
|
||||
scrollIntoView()
|
||||
}, 0)
|
||||
}
|
||||
var location = this._createLocation()
|
||||
this._tree = this.router(location)
|
||||
assert.ok(this._tree, 'choo.start: no valid DOM node returned for location ' + location)
|
||||
|
||||
rerender = nanoraf(function () {
|
||||
if (hasPerformance && timingEnabled) {
|
||||
window.performance.mark('choo:renderStart')
|
||||
}
|
||||
var newTree = router(createLocation())
|
||||
tree = nanomorph(tree, newTree)
|
||||
assert.notEqual(tree, newTree, 'choo.start: a different node type was returned as the root node on a rerender. Make sure that the root node is always the same type to prevent the application from being unmounted.')
|
||||
if (hasPerformance && timingEnabled) {
|
||||
window.performance.mark('choo:renderEnd')
|
||||
window.performance.measure('choo:render', 'choo:renderStart', 'choo:renderEnd')
|
||||
}
|
||||
})
|
||||
this.emitter.prependListener(self._events.RENDER, nanoraf(function () {
|
||||
var renderTiming = nanotiming('choo.render')
|
||||
|
||||
bus.prependListener('render', rerender)
|
||||
var newTree = self.router(self._createLocation())
|
||||
assert.ok(newTree, 'choo.render: no valid DOM node returned for location ' + location)
|
||||
|
||||
assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.render: The target node <' +
|
||||
self._tree.nodeName.toLowerCase() + '> is not the same type as the new node <' +
|
||||
newTree.nodeName.toLowerCase() + '>.')
|
||||
|
||||
var morphTiming = nanotiming('choo.morph')
|
||||
nanomorph(self._tree, newTree)
|
||||
morphTiming()
|
||||
|
||||
renderTiming()
|
||||
}))
|
||||
|
||||
documentReady(function () {
|
||||
bus.emit('DOMContentLoaded')
|
||||
self.emitter.emit(self._events.DOMCONTENTLOADED)
|
||||
})
|
||||
|
||||
tree = router(createLocation())
|
||||
return this._tree
|
||||
}
|
||||
|
||||
return tree
|
||||
}
|
||||
Choo.prototype.mount = function mount (selector) {
|
||||
assert.equal(typeof window, 'object', 'choo.mount: window was not found. .mount() must be called in a browser, use .toString() if running in Node')
|
||||
assert.equal(typeof selector, 'string', 'choo.mount: selector should be type string')
|
||||
|
||||
function emit (eventName, data) {
|
||||
bus.emit(eventName, data)
|
||||
}
|
||||
var self = this
|
||||
|
||||
function mount (selector) {
|
||||
var newTree = start()
|
||||
documentReady(function () {
|
||||
var root = document.querySelector(selector)
|
||||
assert.ok(root, 'choo.mount: could not query selector: ' + selector)
|
||||
nanomount(root, newTree)
|
||||
tree = root
|
||||
})
|
||||
}
|
||||
var renderTiming = nanotiming('choo.render')
|
||||
var newTree = self.start()
|
||||
|
||||
function toString (location, _state) {
|
||||
state = _state || {}
|
||||
var html = router(location)
|
||||
self._tree = document.querySelector(selector)
|
||||
assert.ok(self._tree, 'choo.mount: could not query selector: ' + selector)
|
||||
assert.equal(self._tree.nodeName, newTree.nodeName, 'choo.mount: The target node <' +
|
||||
self._tree.nodeName.toLowerCase() + '> is not the same type as the new node <' +
|
||||
newTree.nodeName.toLowerCase() + '>.')
|
||||
|
||||
var morphTiming = nanotiming('choo.morph')
|
||||
nanomorph(self._tree, newTree)
|
||||
morphTiming()
|
||||
|
||||
renderTiming()
|
||||
})
|
||||
}
|
||||
|
||||
Choo.prototype.toString = function (location, state) {
|
||||
this.state = state || {}
|
||||
|
||||
assert.equal(typeof location, 'string', 'choo.toString: location should be type string')
|
||||
assert.equal(typeof this.state, 'object', 'choo.toString: state should be type object')
|
||||
|
||||
var html = this.router(location)
|
||||
assert.ok(html, 'choo.toString: no valid value returned for the route ' + location)
|
||||
return html.toString()
|
||||
}
|
||||
}
|
||||
|
||||
function scrollIntoView () {
|
||||
var hash = window.location.hash
|
||||
if (hash) {
|
||||
try {
|
||||
var el = document.querySelector(hash)
|
||||
if (el) el.scrollIntoView(true)
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
function createLocation () {
|
||||
Choo.prototype._createLocation = function () {
|
||||
var pathname = window.location.pathname.replace(/\/$/, '')
|
||||
var hash = window.location.hash.replace(/^#/, '/')
|
||||
return pathname + hash
|
||||
|
||||
+10
-10
@@ -4,7 +4,7 @@
|
||||
"description": "A 4kb framework for creating sturdy frontend applications",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "mkdir -p dist/ && browserify index -p bundle-collapser/plugin > dist/bundle.js && browserify index -g unassertify -g uglifyify -p bundle-collapser/plugin | uglifyjs > dist/bundle.min.js && zopfli -i 100 dist/bundle.min.js && wc -c < dist/bundle.min.js.gz | pretty-bytes",
|
||||
"build": "mkdir -p dist/ && browserify index -p bundle-collapser/plugin > dist/bundle.js && browserify index -g unassertify -g uglifyify -p bundle-collapser/plugin | uglifyjs --mangle-props -c unsafe,properties,dead_code,comparisons,evaluate,hoist_funs,if_return,join_vars,pure_getters,reduce_vars,collapse_vars --toplevel > dist/bundle.min.js && zopfli -i 100 dist/bundle.min.js && wc -c < dist/bundle.min.js.gz | pretty-bytes",
|
||||
"deps": "dependency-check --entry ./html.js . && dependency-check . --extra --no-dev --entry ./html.js",
|
||||
"inspect": "browserify --full-paths index -g unassertify -g uglifyify | discify --open",
|
||||
"prepublish": "npm run build",
|
||||
@@ -22,15 +22,15 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bel": "^4.5.1",
|
||||
"bel": "^5.0.1",
|
||||
"document-ready": "^2.0.1",
|
||||
"nanobus": "^3.1.0",
|
||||
"nanohistory": "^1.0.0",
|
||||
"nanohref": "^1.0.0",
|
||||
"nanomorph": "^4.0.0",
|
||||
"nanomount": "^1.0.0",
|
||||
"nanobus": "^4.2.0",
|
||||
"nanohref": "^2.0.0",
|
||||
"nanomorph": "^5.1.2",
|
||||
"nanoraf": "^3.0.0",
|
||||
"nanorouter": "^2.0.0"
|
||||
"nanorouter": "^2.0.0",
|
||||
"nanotiming": "^6.0.0",
|
||||
"scroll-to-anchor": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "^14.3.0",
|
||||
@@ -42,8 +42,8 @@
|
||||
"spok": "^0.8.1",
|
||||
"standard": "^10.0.0",
|
||||
"tape": "^4.6.3",
|
||||
"uglifyify": "^3.0.4",
|
||||
"uglifyjs": "^2.4.10",
|
||||
"uglify-es": "^3.0.17",
|
||||
"uglifyify": "^4.0.1",
|
||||
"unassertify": "^2.0.4"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user