It has been quite a while since the last major version of Choo. Since it's
release, choo@6
has recieved a bunch of features and patches, but some changes
has been put off because they'd have an affect on the API in a way that could be
breaking for some users. With this release we've merged all these minor, but
breaking changes all at once.
The way in which Choo handles hashes in the URL has proved confusing for both
newcomers and seasoned Choo users. In a prior patch the hash
option was added
which could be used to disable hash routing. With this release we're changing it
to be disabled by default.
Rendering pages server side is an excellent way to increase page performance and
Choo supports it out of the box. Choo also allows for rehydrating the client
with what state was used when rendering on the server side. To ensure that the
application state is identicial regardless if hydrated or not, the internals for
routing has been changes so that href
, query
, param
and route
are all
available on application state at the time when stores are initialized.
In prior versions, when rendering on the server, the state that was provided to
toString
would be merged onto the application state. Meaning consecutive calls
to toString
would accumulate on the application state and persist in-between
render. With this change, application state is no longer mutated during server
side render. This will affects those of you doing server side rendering and then
plucking out properties from the application state. You can now be assured that
only the state that is provided to toString
is modified during rendering.
var html = app.toString('/', state)
- var title = app.state.title
+ var title = state.title
And lastly, we've updated depndencies and even dropped a dependency which is
no longer required by modern browsers. The dependency xtend
was dropped in
favour of
Object.assign. This change has also been propagated throughout
the Choo universe i.e. choo-devtools and choo-service-worker etc. If you are
supporting legacy browsers (IE11 and bellow), we recommend the polyfill service
https://polyfill.io which will detect legacy browsers and load the appropiate
polyfills.
That's all for now, keep being awesome!
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.
To top things off, we've reintroduced querystring parsing. An object containing
the current represenation of the search query (e.g. ?foo=bar
) can be found
under state.query
. We used to do something similar in choo v4 and below, and
we're happy to reintroduce it in this release!
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 ✨
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
frame to achieve 60fps. That's why in 5.1.0
we're adding support for the
window.Performance
API.
We hope that by adding support for timers, people building applications on
choo
will become more aware of their application's performance and learn how
and when to optimize. Hopefully this will help in making applications
accessible to all sorts of devices, and not just the latest and greatest.
Timing support will be enabled by default, and can be toggled off by passing
{ timing: false }
to the var app = choo()
constructor.
Timing calls will not run in browsers that don't support it out of the box.
For unsupported browser's there's a polyfill available at
nolanlawson/marky. The timing marks are
choo:renderStart
, choo:renderEnd
. The resulting diff is stored as
choo:render
.
We hope you'll enjoy this release; thanks heaps for using choo!
- added out of the box support for performance timings (
window.performance
) - updated
nanobus
to3.0.0
;'*'
events now run after named events
So it turns out Choo could be radically simplified. We're now comfortably
sitting at ~4kb
, have removed a whole bunch of words from the API and should
be a whole lot faster. We've written about it
before; if you're
interested we recommend reading through that post.
We're now using an event emitter, mutable state and explicit re-renders. Some people might frown at first at the words "mutable state", but if you think it through the mental model doesn't change. "State" has always been a concept of an object that changes over time; we then render the DOM as a snapshot of that state.
What we've done is change the way we mutate that state - we no longer generate a ton of expensive intermediate objects to mutate the state, but instead mutate the state directly. In turn we've also removed the magic re-rendering and made it explicit. This enables people to create tight render loops that can even be used in GC constrained environments like games or music production. We think this change was well worth it, and will make a lot of sense going forward.
People might also wonder why we've moved away from flux
/elm
and are using
an event emitter now. It turns out that the previous architecture had a lot of
confusing words that made it harder to learn than it should. It was also not
possible to react to changes; the thing that changed always had to specify what
needed to respond to it. By using event emitters we've changed this, which will
make relations in the application more expressive. All in all, it turned out
that all we needed for this was a simple event emitter - we think this was well
worth the change and breaking away from what we were previously doing.
Pretty much everything about the API changed in this version. There's literally nothing left to remove from the API tho so this is probably the last time we get to break anything in a significant way.
- ❗ state is now mutable and renders are triggered through
.emit('render')
. - ❗ we've replaced
.use()
,.model()
and the rest of the choo architecture with a reworked.use()
method. It's called once on boot, and exposes a mutable reference tostate
and an event emitter that's compatible with Node'srequire('events').EventEmitter
- ❗ the
.router()
method has been replaced with.route()
, replacing the nested array API. This should be easier to remember and more performant. - ❗ we've replaced
morphdom
/yo-yo
withnanomorph
. The two algorithms are very comparable. The differences are that the new algorithm is smaller and the value of input fields on re-rendering will be whatever thevalue=""
attribute is. - ❗
choo/mount
is now available asapp.mount()
and callsapp.start()
internally now
This patch changes the way we handle routes. It introduces query string support (!), and changes the router to use a lisp-like syntax. It also inverts the argument order of effects and reducers to be more intuitive. We also managed to sneak in some performance upgrades ✨ - We hope you enjoy it!
- ❗ slim down server side rendering API | issue | pull-request
- ❗ update router API to be lisp-like
- ❗ swap
state
anddata
argument order | issue - ❗ remove
choo/http
. Use xhr instead | pull-request - update
router
to use memoization | issue | pull-request - support inline anchor links | issue
- allow bypassing of link clicks in
sheet-router
| issue | pull-request - update router API to handle hashes by default
- update router to provide out of the box support for Electron
- update
location
state to exposesearch
parameters (query strings) | issue
Yay, plugins
now support wrappers
which is a segway onto HMR, time travel
and other cool plugins. These changes have come through in barracks v8.3.0
and a lil fix in v8.3.1
. This is a lil patch before 4.0.0
comes through,
but should be super valuable. Wooh!
- updated barracks to
v8.3.1
Wooh, plugins
are a first class citizen now thanks to the .use()
API. It's
a multiplexed version of the old app = choo(hooks)
. It should enable
attaching multiple hooks onto the same API, which is useful to create re-usable
extensions to choo
. They should be used with care though, and be as generic
as possible, but the docs should provide enough backdrop for that. Anyway,
have fun with plugins! 🎉
- added
app.use()
And another patch down. This time around it's mostly maintenance and a bit of perf:
- The addition of the nanoraf dependency prevents bursts of DOM updates thrashing application performance, quite possibly making choo amongst the fastest frameworks out there.
- We now ship standalone
UMD
bundles on each release, available through https://unpkg.com/choo. The goal of this is to support sites like codepen and the like; this should not be used for production.
Woooh, happy third birthday choo
- thanks dad. You're all grown up now;
look at how far you've come in the last month. You've grown... tinier? But yet
you do more? I love you choo
- shut up dad.
choo
is now 5kb
optimized! That's 2kb
less compared to v2. Woah, how?
We now support yo-yoify which optimizes
those lil template tags to document.createElement()
calls. So not only is it
smaller, creating elements now has no overhead. Pretty nifty eh? Mad shoutout
to Shama for building this!
V3 introduces hooks
- powerful functions that are called at certain points in
the refresh cycle. Unlike functions in models
these functions have unfiltered
access to all properties, call stacks and more. They're super useful when
building error handling, logging or persisting for stuff like hot reloading
.
I quite like them, and I'm def keen to see what uses people will come up with!
effects
are now composable by calling a done(err, res)
callback when
they're done executing. This means that multiple namespaced effects can be
chained together to form some higher level behavior.
Think of cases like "logout" - multiple models must be cleared, perhaps tokens invalidated on the server, all in a certain order. This requires multiple models to work in tandem. - And now that's possible! ✨
We've started work on the choo
handbook - a lil manual to help
you get started, not only with choo, but with web development in general. It's
super modest still, only containing a single choo
tutorial, but we'll be
expanding this over the coming months. If you want to contribute some docs,
there's a whole section of
ideas on stuff that
might be neat to write. Any lil bits are welcome! Shout out to
Tim for making this happen 🎉
views
have gone through a bit of a change - they're now required using
require('choo/html')
so they can be factored out of a project into standalone
bel components at any time. But additionally
these components have gained super powers through the adition of onload
and
onunload
hooks. Components can now react to being mounted or not, which makes
them ideal to implement standalone widgets. This behavior uses html5
MutationObserver
under the hood, so it will work anywhere with a DOM! Again, this was all
Shama's hard work.
choo
has gained a beaut blanket of tests, courtesy of
Todd and
Ben. We've got server, browser and
pretty-much-all-browsers-known-to-mankind style testing which should give us
a pretty good idea if stuff breaks. Neat!
Internally we've moved the core of choo
into a separate package -
barracks. choo
is now mere glue
code around barracks
, yo-yo
and sheet-router
. This is good news for folks
who like choo
, but don't agree with all decisions. Go forth and build your
own lil framework!
- move
choo.view
out torequire('choo/html')
#71 | pr #103 - streamline view API #35 | pr #111
- higher order functions #34 | pr #104
- create lifecycle hooks #1 | feature addition in dependency covered by semver
- implement state hooks #15 | pr #104
- add yo-yoify #3 | pr #110
- rename "app" namespace #82 | pr #111
- enable browser testing | pr #86
- propagating actions creates infinite loop #114 | pr #104
- state is now immutable in
reducers
andeffects
Huge thanks to everyone who's collaborated on this, provided feedback or even mentioned it anywhere. It's been a hella lot of people, but seriously, you're the best 🚂🚋🚋🚋🚋🚋
- 76 - fix router arguments
- 55 - load subscriptions once DOM is ready
- heaps of documentation fixes; looks like choo is taking off 🐨
- namespaces are now enforced more strictly
- models now only accept a single argument
- the
namespace
key was introduced inside of models (was prior the leading string in models) - namespaced models can now only operate within themselves
- first version of choo