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.
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.
All code was reformatted with Prettier. This required
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,
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
to a modern ES6 class with a single click in VSCode, passing all tests bar one:
you cannot instantiate a ES6 class without the
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
of Grunt config with the command
parcel build src/mopidy.js.
Reducing runtime dependencies
The time had now come to runtime dependencies.
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
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.
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
yarn start now runs the demo web app on
automatic code reloading on source changes.
For the Node.js console
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 wild fire 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 VSCode. 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 was 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, there’s a number of VSCode extensions that can automatically generate a ToC and keep it up to date every time you save your file.
I’d actually 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!