To celebrate the release of Meteor 1.2 and built-in support for ES6 syntax, I’ve been playing with implementing some of my favorite Object Oriented design patterns in JavaScript. While doing this, I quickly ran into an interesting quirk of the Meteor package system. I began by writing creating a class in a Meteor package:
class CommandHandler {
...
}
Next, I added an export for CommandHandler
in the package’s package.js file:
api.export('CommandHandler');
But interestingly, CommandHandler
was undefined
in my Meteor application. What’s going on here?
A quick session in the Babel REPL shows that a plain class decleration will compile down to a locally scoped function:
class CommandHandler {}
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var CommandHandler = function CommandHandler() {
_classCallCheck(this, CommandHandler);
};
This type of function declaration will not be picked up by the api.export
method. Only package-level variables, or variables declared without a var
, let
, or const
, are exportable. A quick fix to our class definition would be to tie our class definition to the global scope:
CommandHandler = class CommandHandler {}
This declaration compiles down to the following JavaScript:
CommandHandler = function CommandHandler() {
_classCallCheck(this, CommandHandler);
};
We can get more concise about it and use an unnamed class expression:
CommandHandler = class { }
Which compiles down to:
CommandHandler = (function () {
function _class() {
_classCallCheck(this, _class);
}
return _class;
})();
When using unnamed class expressions, it’s important to remember that certain features like this.constructor.name
cannot be used within your class.
Notice that the CommandHandler
function is now being declared on the global scope. Now api.export
will happily pick up our CommandHandler
declaration and we can use it within our Meteor application.
Happy ES6ing!