Writing Hubot scripts using ES6+
Since I discovered it shortly after moving into the world of Hipchat (and later Slack) from the world of IRC, Hubot has been one of my favorite tools to make my life better. I’ve always enjoyed ChatOps, from the early days when we simply called it “writing eggdrop scripts,” and Hubot brought ChatOps into the modern age with its infinite flexibility and common platform that everyone could build on top of.
Hubot itself is written in CoffeeScript, and traditionally, most scripts have also been written in CoffeeScript. Unfortunately, I don’t like CoffeeScript much—I’ve always found it to be an ill-fitting crutch for Ruby developers who didn’t want to learn JavaScript, lest they cut themselves on the sharp edges of braces. Meanwhile, ES6 (ES2015, really, but I’m set in my ways…) has brought some really nice things to JavaScript development. I’m not going to list any here, but take a look at kangax’s ES6 compatibility table for an exhaustive list of everything ES6 brings to the table.
I’ve been slowly converting the scripts we use internally at Xamarin to at least be written in JavaScript, if not ES6—there hasn’t really been any good guidance on how to plug ES6 scripts into Hubot until recently, and what there was seemed like it was only half of the story. Today I sat down and figured out what needed to be done to make ES6 scripts automatically work.
Step 1: Install a few packages
Install
babel-register
,
babel-preset-es2015
, and
babel-plugin-add-module-exports
. Visit the respective module sites to learn more about them,
but the short story is that the first two will make sure Babel
works, and the last package makes sure Babel exports
CommonJS-style defaults so that simple
require
calls will work.
Step 2: Create a .babelrc
At the top-level of your Hubot repo, create a
.babelrc
file with the following contents:
{
"presets": [ "es2015" ],
"plugins": [ "add-module-exports" ]
}
This will enable the ES6 preset and the
module.exports
plugin you installed earlier.
Step 3: Make sure Babel gets loaded early
Create a script that will be always be loaded first—I chose to
name mine
000-import-es6.js
. You can also make this a CoffeeScript script if you’d like,
but I stuck with plain old JavaScript. The contents should look
like this:
require("babel-register");
module.exports = function es6(robot) {};
The function export is not, in fact, required—it just makes
Hubot shut up about expecting a function but receiving an object
when checking
module.exports
.
Step 4: Profit!
You can now write scripts using ES6—all of the features are available to you to use. Put your scripts in the standard location for Hubot and they will happily be loaded and compiled at runtime—you’ll still get correct line numbers in stack traces though, for which I am infinitely thankful.
For Module Authors
If you’re authoring a Hubot module outside of your
Hubot source tree, the process is almost exactly the same—at
step 3, instead of creating a
000-import-es6.js
file, you can create an
index.js
in the root of your package, with contents similar to this:
require("babel-register");
var realDefault = require("./src/foo");
module.exports = realDefault;
A possible alternate solution is to require
babel-register
, then export a function that uses Hubot’s
robot.loadFile
method to load your actual script entry point—I haven’t tried
this, so I don’t know how well it would work, but I suspect it
would be just fine.
Leave a comment