Yesterday, I released v1.0.0 of the Mopidy.js JavaScript library. Even though the library serves as the basis for most Mopidy web clients and has been in active use since 2013, this was the first release in almost four years.
Four years is quite a long time in the world of JavaScript.
In the beginning of October, I stopped bundling Mopidy.js with the Mopidy Python project and thus had to update the Mopidy.js documentation. While doing so, I tried to run the test suite, written using Buster.JS, which has been abandoned for a few years. To no avail, npm and Yarn were not able to install the library’s development dependencies.
After four years of standing still while the fast-moving world of JavaScript sped on, I seemed forced to spend some time on modernizing the library and it’s development tooling to ensure that it would be maintainable going forward.
I asked a couple of coworkers for advice on what to replace Buster.JS with that could test a library in both Node.js and the browser, and what they would use instead of Browserify today. I was quickly pointed towards Jest for testing and Parcel for zero-configuration builds.
Porting the full test suite–three times the size of the library–to Jest was work, but mostly mechanical work. The only part I needed to read a bit up on was Jest’s mocking capabilities compared to Sinon.JS.
Modernizing development tooling
After getting the test suite running again the modernization continued.
JSHint and a list of rules were replaced with ESLint and Airbnb’s style guide.
All code was reformatted with Prettier. This required
almost no
configuration,
once figuring out how to make ESLint and Prettier stay friends. However, the
experience of getting an entirely consistent code style without any effort is
priceless. I can accept most differences from my previous styles in exchange
for not having to do the work myself and not having to enforce that my
contributors and coworkers do the same. Formatters like Prettier,
Black, gofmt
, and rustfmt
are here to stay
and will probably be an integral part of all new programming languages.
The Mopidy.js code was originally hand-written ES5 using all the hard-learned
tricks of the trade from David Herman’s splendid book Effective
JavaScript. At least it was splendid in 2013. Now it
was
converted
to a modern ES6 class with a single click in VS Code, passing all tests bar one:
you cannot instantiate an ES6 class without the new
keyword.
Removing Buster.JS and JSHint reduced the project’s Grunt setup a bit. The move
from Browserify for browser builds and Uglify for minification to Parcel lead
to the removal of Grunt entirely, and the replacement of a monitor height or
two
of Grunt config with the command parcel build src/mopidy.js
.
Reducing runtime dependencies
The time had now come to runtime dependencies.
The faye-websocket
package was replaced with the
ws package, which made it possible to
replace our own Node.js/browser compatibility
layer
for WebSocket usage with
isomorphic-ws.
Since the last release of Mopidy.js in 2015, ES6’s Promise implementation has become quite universally available. Thus, when could be replaced with Promise, shrinking the minified library from 42 kB to 12 kB.
BANE, an event emitter library that was
part of the now-dead Buster.JS testing tool, was replaced with the
EventEmitter
implementation from Node.js’ standard library. Parcel
helpfully and entirely automatically included the EventEmitter
implementation
from Node.js as part of the web bundle, without having to add a dependency on
one of the npm packages that has
extracted this lib from the Node.js standard library.
Making demo applications
Once everything was modernized, I added two demo applications to the project.
The
web-based
application is served by Parcel’s web server. The configuration needed? Add
parcel examples/web.html
as the start
script in package.json
and I was
done: yarn start
now runs the demo web app on http://localhost:1234
, with
automatic code reloading on source changes.
For the Node.js console
application,
I quickly remembered that while promises are better than callbacks, they can
still quickly become quite mind-boggling to work with. Enter async/await,
spreading like wildfire from language to language the last few years, and
fully available in Node.js since 2017. You just have to remember to create all
the promises you need, and only then await
them. This makes it possible for
the promises to be fulfilled in parallel instead of sequentially, avoiding that
the sequential round trip times to the server add up.
Somewhere around here I read a bit up on TypeScript and tested out porting the library to TypeScript with great help from VS Code. Due to Mopidy.js’ tiny static API and quite large dynamic API, automatically generated based on the API description retrieved from the server, this didn’t seem a worthy path to go down this time around. However, the experience was a good one, and I’ll probably revisit TypeScript in the future on other projects.
Finally, the Mopidy.js docs were moved from the Mopidy docs to the Mopidy.js project and updated accordingly. Being used to writing docs in Sphinx, Markdown’s lack of features like generating a table of contents can feel limiting. Of course, several VS Code extensions can automatically generate a ToC and keep it up to date every time you save your file.
Wrapping up
In the late 1990s, I tweaked JavaScript-based web calculators. In the 2000s I surfed with JavaScript disabled and required apps we built to work without it. From 2011 through 2015, I spent a small majority of my time in frontend JavaScript. Since the summer of 2016, I’ve done very little, if any, JavaScript.
It seems that my relationship with and usage of JavaScript varies like the tide, even if on another time scale. After a while away, JavaScript as of late 2018 seems to be in a lot better place than in 2015. The language is nicer. The chore of project setup and maintenance is reduced. Tooling is better, and way better integrated. I’ve felt the JavaScript fatigue before, but from my perspective, it seems like many things are stabilizing in a quite good place.
I’d go as far as claiming that the exercise of modernizing Mopidy.js and its development tooling was, at times, fun and inspiring.
Here’s to four more years of Mopidy.js. Then I might be back with a port to WebAssembly, implemented in Rust, or a language yet to be designed. We’ll see!
This blog post was originally published at jodal.no.