Meteor 1.3 is upon us! It brings with it promises of better testability, reusability and debugability all thanks to the ES6 module system.
Unfortunately, a wholesale transition into the 1.3-style of doing things may take a huge amount of work, depending on the size of your application. Where will you find the time to refactor your entire application into modules?
Even a partial transition can be frustrating.
Imagine you have a collection called MyCollection
that you’ve decided to move into a module. This process is simple enough. After your refactor, you might have a module located at /imports/lib/mycollection
that exports MyCollection
:
import { Mongo } from "meteor/mongo";
export default new Mongo.Collection("mycollection");
The difficulty comes in when you realize that the rest of your 1.2-style application still assumes that this collection will be accessible as a global reference.
When you run your application, you’ll be greeted by countless errors complaining that MyCollection
is not defined throughout your application:
ReferenceError: MyCollection is not defined
One possible solution to this problem is to find each file referencing this collection and import MyCollection
module within it.
import MyCollection from "/imports/lib/mycollection";
...
MyCollection.find(...);
However, if your application references this collection throughout dozens or hundreds of files, this can quickly get out of hand. The seemingly simple process of moving MyCollection
into a module has suddenly turned into a hydra requiring you to edit files throughout your entire project.
Another solution to this problem is to import MyCollection
globally on both your client and your server. This eliminates the need to modify potentially hundreds of files throughout your project, and lets your legacy 1.2 code exist in blissful harmony with your 1.3 modules.
But how do we import modules globally? It’s not as simple as just importing them in your project’s main.js
files. After all, ES6 import
calls are transpiled down to var
declarations by Babel, and var
scope is limited to the file it was declared in.
The key is to import your module into your local scope and then explicitly assign it to a global reference. Using this technique, your client/main.js
and server/main.js
would look something like this:
...
import _MyCollection from "/imports/lib/mycollection";
MyCollection = _MyCollection;
If your collection is a named export, rather than a default export, you can assign it to a global reference like this:
import { MyCollection as _MyCollection }
from "/imports/lib/mycollection";
MyCollection = _MyCollection;
Transpired down to ES5, our import looks something like this:
var _mycollection = require("/imports/lib/mycollection");
MyCollection = _mycollection.MyCollection;
Notice that we’re reassigning the locally scoped _mycollection
to the global MyCollection
reference. Now, your old 1.2 style code can continue to reference MyCollection
as a global.
Happy refactoring!