TLDR
Meteor supports FlowType via the ecmascript package, but requires some setup to support import statements for Meteor packages and so called class properties. By adding a .flowconfig file and a babel plugin, everything should work smoothly. See the details below on how to do this.
Introduction
This tutorial will help you get started with FlowType in Meteor. It won't go into much detail about why you should use FlowType, or why I prefer it over TypeScript. In short, FlowType adds strong-typing to your Javascript code, which can help you prevent bugs. It's also more opt-in than TypeScript. TypeScript is great when your whole codebase has been written in it, but a lot harder to introduce incrementally.
This is what Facebook, the creator of Flow, has to say about it:
Flow's type checking is opt-in, which means you can gradually convert your existing JavaScript codebase to Flow while reaping incremental benefits. You don't need to rewrite your existing codebase to start using Flow.
FlowType has been supported since the ecmascript package was added to Meteor. It allowed us to add type definitions/annotations to our Javascript code, but when actually running Flow on our Meteor codebase it would give us some issues: Meteor specific package import statements and the lack of support for class properties. Let's fix that!
Setup
Meteor 1.3.3 or higher with the ecmascript
package.
# install meteor
curl https://install.meteor.com/ | sh
# Update to 1.3.3 if you are on a lower version
meteor update --release 1.3.3
# ecmascript package is automatically included
Flow 0.25.0 or higher
meteor npm install flow-bin --save-dev
Support importing Meteor packages
Meteor has its own import naming convention for packages:
import { FlowRouter } from "meteor/kadira:flow-router";
All the packages get a meteor/
prefix. Flow doesn't know how to handle that by default.
Also, absolute paths which are supported in Meteor will give Required module not found
errors:
import Todos from "/collections/todos";
By tweaking the .flowconfig
file, we can make Flow actually resolve those paths. We do that by adding some module.name_mapper
options:
[options]
# Absolute path support:
# e.g. "/collections/todos"
module.name_mapper='^\/\(.*\)$' -> '<PROJECT_ROOT>/\1'
# Meteor none core package support
# e.g. "meteor/kadira:flow-router"
module.name_mapper='^meteor\/\(.*\):\(.*\)$' -> '<PROJECT_ROOT>/.meteor/local/build/programs/server/packages/\1_\2'
# Meteor core package support
# e.g. "meteor/meteor"
module.name_mapper='^meteor\/\(.*\)$' -> '<PROJECT_ROOT>/.meteor/local/build/programs/server/packages/\1'
# Fallback for Meteor core client package
# e.g. "meteor/meteor"
module.name_mapper='^meteor\/\(.*\)$' -> '<PROJECT_ROOT>/.meteor/local/build/programs/web.browser/packages/\1'
[ignore]
# Ignore the `.meteor/local` packages that aren't important
.*/.meteor/local/build/programs/server/app/.*
.*/.meteor/local/build/programs/server/assets/.*
.*/.meteor/local/build/programs/server/npm/.*
.*/.meteor/local/build/programs/server/node_modules/.*
.*/.meteor/local/build/programs/web.browser/app/.*
.*/.meteor/local/build/main.js
.*/.meteor/packages/.*
# This package can give you a lot of flow errors, better ignore it
.*/node_modules/fbjs/.*
Class properties in Meteor
Let's create an ES2015 class! This is a basic feature, but Flow requires us to define the type of a class property:
// @flow
class Todo {
constructor(name: string) {
// Flow warning: Property 'name' not found in Todo
this.name = name;
}
}
But what happens when we add that property to our class? Meteor crashes, because it doesn't support transforming class properties, because that hasn't reached maturity yet.
// @flow
class Todo {
// Meteor crash: Class properties not supported
name: string;
constructor(name: string) {
this.name = name;
}
}
Luckily, since Meteor 1.3.3 adding babel plugins is supported. Let's add the transform class properties plugin, so Meteor will not crash when we define class properties required by Flow.
First install the plugin via npm:
meteor npm install --save babel-plugin-transform-class-properties
And then add the plugin via the .babelrc
file (or package.json
).
{
"plugins": [
"transform-class-properties"
]
}
Mind you, only plugins and presets are supported at the moment.
When Meteor restarts, everything should work and Flow should be happy:
$> flow
No errors!
Conclusion
Flow is pretty awesome and with only some small tweaks in your setup you can get it fully working with Meteor. These tweaks have been working for me in small applications, but I wonder if you run into any issues for your project.
If you have any issues, tips or tricks on using Flow with Meteor, please let me know!