Did you know that you can write command line programs with meteor? We’ve been doing this for quite some time now, since we got tired of of copying our server side meteor code into npm packages just in order to run batch, cron and on-demand jobs that share a lot of code with our webapp (we are DRY OCDs here).

We also preferred meteor’s cleaner requireless approach of writing code, reactive programming using meteor’s mongo and tracker packages, and using meteor’s ddp package, rather than the npm alternatives.

So, let’s see how to do that.

Show me the main’y

Every meteor app needs a single global main function which meteor calls to get the app going.

When you meteor create an app, meteor automatically adds the meteor-platform package to the app. This package automatically includes all the packages needed to create a meteor web app in your app, by api.implying them.

One of the packages it includes is the webapp package, which exports a main function that gets the web server running in your app.

In order to create a command line app, you will need to remove the meteor-platform package, add back the core meteor packages you want to use, and add a global main function. Let’s do that:

meteor create cli
cd cli

# Let's see what packages meteor added for us
cat .meteor/packages

# You will get a list of all the packages that meteor-platform included
meteor remove meteor-platform

# No need for those packages in a clientless app
meteor remove autopublish insecure

# Let's add back the core meteor environment, including the Meteor object and some of it's APIs
meteor add meteor

# We'll want back access to our mongodb collections using meteor's Mongo api
meteor add mongo

# How about some meteor server side reactive programming using meteor's Tracker api
meteor add tracker

# In case we want to access some 3rd party APIs using meteor's HTTP api 
meteor add http

# We don't need any client side or shared files in our server side app
rm cli.*

# Let's create the server folder which will store our main.js
mkdir server
cd server

Now, in the server folder, create a main.js file with your own main function:


main = function(argv) { console.log("I'm a meteor command line program!"); };

Let’s run our app, see what goes. You’ll need to run meteor with –once, since otherwise, everytime your program exits, meteor will restart it:

cd ..
meteor --once

Wuala! You just created your first meteor command line program.

As a learning experience, let’s run the app again, this time without –once, see what happens:

meteor

Familiar message, isn’t it? We got it because when you run meteor, meteor actually starts two programs, not one. The first one is a meteor web proxy app which is also responsible for:

  • Starting your actual meteor app (the 2nd program).

  • Trying to restart it every time it exists, because it assumes it crashed, which is usually the case with web apps, but not with command line programs.

  • Restarting your app every time it detects file changes in your app.

This is also why you get the application is crashing message in your browser, when a meteor web app crashes. The meteor web proxy is the one serving it, not your actual app.

Using the same mongodb in your web app and your command line program(s)

In development mode, every meteor app has it’s own internal mongodb that is located inside an app’s .meteor/local folder.

Therefore, if you want to share a mongodb between your webapp and your command line programs, you will need to use an external mongodb and export the MONGO_URL environment variable so your meteor apps can connect to it. I recommend a free sandbox database from compose.io (formerly mongohq), but there are other alternatives out there as well.

Handling command line arguments – practicalmeteor:mcli to the rescue

Since meteor doesn’t support command line arguments, and relies on Meteor.settings instead, we have created the practicalmeteor:mcli package, which is a package and scripts for easily creating and running command line programs, including support for command line options and arguments. It provides you with the following:

  1. A starter meteor command line program (along the lines of meteor create), which will get you going immediately.

  2. Support for registering multiple commands in the same command line program, using CLI.registerCommand()

  3. Support for registering asynchronous / daemon commands, that don’t exit immediately.

  4. The mcli script, which allows you to run your commands with options and arguments.

  5. Support for easily specifying default values for command line options.

For additional howto info, refer to the package’s README.

Known Issues

  1. You will not be able to use packages that depend directly or indirectly on any of the accounts packages. I’m working on a meteor pull request to solve this issue. You can see the issue here, and an outdated PR here.

  2. As a consequence of the above, the Meteor.users property will not be defined in the Meteor object. To workaround it, you can just define it yourself, pointing to the same collection:


Meteor.users = new Mongo.Collection('users');

Possible Applications

  1. Writing app specific load and stress testing tools using DDP.connect.

  2. Sending handlebars formatted emails to your customers using the excellent handlebars-server package.

  3. Sending spacebar formatted emails using the excellent ssr package from the living community legend arunoda :)

  4. mongodb data cleanup, maintenance and “schema” upgrade tools.

  5. Writing npm packages with meteor (YES YOU CAN!). On that, in a future post.

  6. And many many many many many (did i put enough many’s???) more.