What’s coming in choo v5

Yoshua Wuyts
choo
Published in
4 min readMar 4, 2017

🚂🚃🚃🚃🚃🚃🚃🚃🚃🚃

These are notes on the next version of choo, a sturdy frontend framework. It’s by no means close to done, but I feel the general direction is solid and I want to share some of the process while it’s still fresh.

So why change things?

I recently got a job 🎉🎉🎉🎉. This means not only working with some of the kindest humans I know — it’s also meant that I got to test a lot of my work in the wild. I’ve had a good chance to see where people struggle learning, which abstractions started to break down and how we could improve all that.

Another thing that comes into play is that the current version of choo is hilariously unsuited for any performance sensitive-realtime work. Much like other frontend frameworks, it creates a lot of garbage on every update — which means when the time comes to collect the garbage, the application takes a rather long break. In most programs you won’t notice this, but when live-editing multiple audio streams this delay can be catastrophic.

So what’s changing?

Mutable state

First off state is going to become mutable. At the moment state is immutable at any given time. But given that views are snapshots of the state anyway, it makes no sense to also make the state immutable — it creates unnecessary work for the garbage collector so we’re tossing it out.

New model API

By making state mutable, we can change the model API. Models are choo’s abstraction for managing data. In the current version there’s a lot of words to learn and some of the APIs are rather quirky. We’re going to remove all the method names, and just have a callback that receives the state.

var app = choo()
app.model(function (state, bus) {
console.log('state is', state)
})

Reactive programming

It turns out flux-like architectures are rather hard to deal with in real-world scenarios. Using event emitters is simpler to reason about, and more expressive. We’ll be using Node’s require('events') API. If you're familiar with how Node works this should be very intuitive. It also means less words to learn.

var app = choo()
app.model(function (state, bus) {
bus.on('foo', function () {
console.log('foo called')
})
bus.emit('foo')
})

A shiny diffing algorithm

We’ll probably put nanomorph in there instead of the current diffing engine. It might be a little buggy, but the perf increase / API stability will be worth it.

Transparent DOM updates

Rather than having odd message orders, re-rendering the DOM will be done by calling emit('render').

Lazy loading applications

Traditionally it wasn’t possible to declare models after the application had started. This will now be possible, which enables code splitting. This was probably one of the most sought-after features that we couldn’t deliver on, until now.

Components

Last, but not least we’ll be adding components. nanocomponent was written a little while back, and it’s pretty neat. It allows creating framework-agnostic elements that have a whole range of lifecycle events and has built-in caching of elements. It even allows using fancy new APIs like window.requestIdleCallback and window.InterSectionObserver. Very neat-o.

What are we losing?

~25% size

Some quick testing indicates that choo will now be ~4kb. Not that it matters at that point, but yeah we’re shedding a few bytes.

Plugins

Choo currently has a rather rich plugin system. By switching to event emitters plugins won’t be needed anymore, as it’s much easier to keep track of what’s going on. By using the .on('*') event you can even listen to all events, which is useful for things like logging.

Namespaces

Namespaces are being moved out of choo, and into userland. This means that namespacing events becomes convention-based and can be used where needed. Given that the current namespacing abstraction is shaky at best, this change will probably feel like a big relief.

So what’s next?

It’s hard to promise we’ll never break things, but I think choo should be in an OK place at v5. There’s little left to remove in both API and code.

It’d be cool if we could go into something close to maintenance mode, kind of like how browserify and level are in maintenance mode. One can dream though; but yeah I feel we're getting one step closer.

And that’s it — I hope this somewhat explained what’s coming next for choo. If you’d like to run some of this code, there’s now a repo up with an executable API sketch.

If you liked these words, I also write words over on birdfeed. Chao! ✌️

Cross-posted from https://github.com/yoshuawuyts/writing

Edit: choo 5 has been released! Almost everything from these notes made it in, with a few exceptions.

  1. we dropped components because they’re kind of a separate concern. Nanocomponent is a rather opinionated package, and having it live separately is fine — instead we’re documenting the caching patterns so anyone can write their own package.
  2. We renamed .model() to .use() — it turned out this was easier for people to remember.
  3. We switched to nanorouter, a tiny router with even less overhead than sheet-router. We removed the lisp-like syntax we had before, and introduced a .route() API. This should cut down boot times by a bunch.

We hope this makes sense; enjoy choo 5

--

--