From bddcfbe838712aacb768ef5d118430d485105647 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Fri, 30 Mar 2018 18:19:06 +0200 Subject: [PATCH 01/12] choo components (#639) * add components * example: componentize header * fix choo SSR * example: componentize footer * example: fix footer * update component cache asserts * componentize todos * reorder example dir * fix example tests * fix dep check test * Add garbage collection of unused components * Apply args when calling identity * update to new component preview * update nanocomponent * fix cache err name * remove static methods from example * restore app.emit() function * public API tests * offset component cache iteration by 2 * whitelist contents of component folder (#643) * allow lru number arg * fix lint typo --- component/cache.js | 41 +++++ component/index.js | 1 + example/components/footer/clear-button.js | 15 ++ example/components/footer/filter-button.js | 18 ++ example/components/footer/index.js | 50 ++++++ example/components/header.js | 32 ++++ example/components/info.js | 16 ++ example/components/todos/index.js | 65 +++++++ example/components/todos/todo.js | 64 +++++++ example/index.js | 10 +- example/{store.js => stores/todos.js} | 47 ++--- example/test.js | 21 +-- example/view.js | 190 --------------------- example/views/main.js | 21 +++ index.js | 57 +++++-- package.json | 6 +- test.js | 16 ++ 17 files changed, 411 insertions(+), 259 deletions(-) create mode 100644 component/cache.js create mode 100644 component/index.js create mode 100644 example/components/footer/clear-button.js create mode 100644 example/components/footer/filter-button.js create mode 100644 example/components/footer/index.js create mode 100644 example/components/header.js create mode 100644 example/components/info.js create mode 100644 example/components/todos/index.js create mode 100644 example/components/todos/todo.js rename example/{store.js => stores/todos.js} (83%) delete mode 100644 example/view.js create mode 100644 example/views/main.js 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` + + ` + + 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`
    +

    todos

    + +
    ` + } + + 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`
    + this.toggleAll()}/> + + +
    ` + } + + 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..5a3606d2 --- /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` +
  • +
    + + + +
    + +
  • + ` + + 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` -
    -

    todos

    - -
    - ` - - 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` - - ` - - function deleteAllCompleted () { - emit('todos:deleteCompleted') - } - } -} - -function TodoItem (todo, emit) { - var clx = classList({ completed: todo.done, editing: todo.editing }) - return html` -
  • -
    - - - -
    - -
  • - ` - - 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/index.js b/index.js index c29ab82d..79a7c525 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 = [] 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 this.emitter.prependListener(this._events.DOMTITLECHANGE, function (title) { @@ -76,11 +83,11 @@ Choo.prototype.route = function (route, handler) { Choo.prototype.use = function (cb) { assert.equal(typeof cb, 'function', 'choo.use: cb should be type function') var self = this - this._stores.push(function () { + this._stores.push(function (state) { var msg = 'choo.use' msg = cb.storeName ? msg + '(' + cb.storeName + ')' : msg var endTiming = nanotiming(msg) - cb(self.state, self.emitter, self) + cb(state, self.emitter, self) endTiming() }) } @@ -128,8 +135,9 @@ Choo.prototype.start = function () { } } + this._setCache(this.state) this._stores.forEach(function (initStore) { - initStore() + initStore(self.state) }) this._matchRoute() @@ -200,9 +208,10 @@ Choo.prototype.toString = function (location, 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') - // TODO: pass custom state down to each store. + var self = this + this._setCache(this.state) this._stores.forEach(function (initStore) { - initStore() + initStore(self.state) }) this._matchRoute(location) @@ -236,3 +245,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..cdc8e2ee 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,14 @@ "html/index.js", "html/raw.js", "html/index.d.ts", + "component/cache.js", + "component/index.js", "dist", "example" ], "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", + "deps": "dependency-check --entry ./html/index.js . && dependency-check . --extra --no-dev --entry ./html/index.js --entry ./component/index.js", "inspect": "browserify --full-paths index -g unassertify -g uglifyify | discify --open", "prepublishOnly": "npm run build", "start": "bankai start example", @@ -34,8 +36,10 @@ "bel": "^5.1.3", "document-ready": "^2.0.1", "nanobus": "^4.2.0", + "nanocomponent": "^6.5.0", "nanohref": "^3.0.0", "nanolocation": "^1.0.0", + "nanolru": "^1.0.0", "nanomorph": "^5.1.2", "nanoquery": "^1.1.0", "nanoraf": "^3.0.0", diff --git a/test.js b/test.js index cb748542..a8880d4a 100644 --- a/test.js +++ b/test.js @@ -29,3 +29,19 @@ tape('should render on the server with hyperscript', function (t) { t.equal(res.toString().trim(), exp, 'result was OK') t.end() }) + +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() +}) From 4c6985c81979150c3b3cd8e1a82ab689d3cd17fd Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Fri, 30 Mar 2018 18:49:08 +0200 Subject: [PATCH 02/12] v6.11.0-preview1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cdc8e2ee..c35802e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "choo", - "version": "6.10.3", + "version": "6.11.0-preview1", "description": "A 4kb framework for creating sturdy frontend applications", "main": "index.js", "files": [ From 4f50c0ae34ee6c5b232094100d597c9fab498fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Wed, 4 Apr 2018 12:28:49 +0200 Subject: [PATCH 03/12] Switch to nanohtml (#644) --- html/index.d.ts | 4 ++-- html/index.js | 2 +- html/raw.js | 2 +- package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) 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/package.json b/package.json index c35802e4..36cff79b 100644 --- a/package.json +++ b/package.json @@ -33,11 +33,11 @@ ], "license": "MIT", "dependencies": { - "bel": "^5.1.3", "document-ready": "^2.0.1", "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", From 948a4f8a26033d0f3bb33ec77243e4485cce16bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Wed, 4 Apr 2018 12:29:01 +0200 Subject: [PATCH 04/12] Use nanoassert in the browser (#651) --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 36cff79b..45a0d0f1 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,12 @@ "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 --entry ./component/index.js", + "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", @@ -34,6 +37,7 @@ "license": "MIT", "dependencies": { "document-ready": "^2.0.1", + "nanoassert": "^1.1.0", "nanobus": "^4.2.0", "nanocomponent": "^6.5.0", "nanohref": "^3.0.0", From 4ee1e774d393bc1b2f72c2e44a15648d46709c34 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 22 May 2018 10:58:41 +0200 Subject: [PATCH 05/12] 6.11.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45a0d0f1..68053b0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "choo", - "version": "6.11.0-preview1", + "version": "6.11.0", "description": "A 4kb framework for creating sturdy frontend applications", "main": "index.js", "files": [ From b0cdb6cd63e70207e8822af03cfa3de27a978984 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 23 May 2018 09:28:38 +0100 Subject: [PATCH 06/12] Build for UMD (#617) * Build for UMD 8 characters. See choojs/choo#537 * Export UMD as 'Choo' instead, export choo/html also * Don't export choo/html in all circumstances --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 68053b0d..5b54a83f 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "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", + "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", From 983f33637f43b73466ba1fa4040b118ecbb4ff1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Tue, 5 Jun 2018 15:58:08 +0200 Subject: [PATCH 07/12] Update bel and yo-yoify references in docs to nanohtml. (#660) --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 From ffd41dfbcdafb4f664ba8249819f1a368c485f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Tue, 5 Jun 2018 16:04:57 +0200 Subject: [PATCH 08/12] =?UTF-8?q?ci:=20Node=207=20=E2=86=92=20Node=2010=20?= =?UTF-8?q?(#661)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: From 1d9b544626141d5279b7efb382387dadc04895c7 Mon Sep 17 00:00:00 2001 From: Yerko Palma Date: Tue, 5 Jun 2018 10:44:46 -0400 Subject: [PATCH 09/12] update dependencies (#663) --- example/components/todos/todo.js | 2 +- package.json | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/components/todos/todo.js b/example/components/todos/todo.js index 5a3606d2..231e3acb 100644 --- a/example/components/todos/todo.js +++ b/example/components/todos/todo.js @@ -47,7 +47,7 @@ function Todo (todo, emit) { } function handleEditKeydown (e) { - if (e.keyCode === 13) update(e) // Enter + if (e.keyCode === 13) update(e) // Enter else if (e.code === 27) emit('todos:unedit') // Escape } diff --git a/package.json b/package.json index 5b54a83f..f9125465 100644 --- a/package.json +++ b/package.json @@ -53,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" } } From 61ff2978c36db05c576d3fae74be76d8dec829ee Mon Sep 17 00:00:00 2001 From: Sean Genabe Date: Mon, 11 Jun 2018 16:51:56 +0800 Subject: [PATCH 10/12] typings: add app to app.use cb (#665) --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From ac92939c8481a48406088c7be1c90d5d50aa168e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Wed, 13 Jun 2018 15:43:19 +0200 Subject: [PATCH 11/12] 6.12.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f9125465..242a4d84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "choo", - "version": "6.11.0", + "version": "6.12.0", "description": "A 4kb framework for creating sturdy frontend applications", "main": "index.js", "files": [ From c3a640182cc00380682660e83d14219313bc4a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Wed, 13 Jun 2018 15:46:09 +0200 Subject: [PATCH 12/12] 6.12.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 242a4d84..09e1ff19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "choo", - "version": "6.12.0", + "version": "6.12.1", "description": "A 4kb framework for creating sturdy frontend applications", "main": "index.js", "files": [