If you haven’t heard about the new framework for rapid prototyping and development, then you should certainly check Meteor’s website and the examples.

Meteor is very fun to write with, and it’s very modern and clean.

It’s not all rainbows and unicorns, though, and learning the “right way” of doing things might take some time. When starting with Meteor, I got stuck with problems that had no solution on the Internet - much more than once. Here I’d like to share the most common of them, the best practices, and the mindset you should have behind every Meteor project to turn it into a success instead of a big disappointment.

Meteor Packages

The recently released version 0.9.0 introduced a new built-in packaging system to Meteor. Before that, you had to install a third-party package manager called Meteorite. Now it all comes embedded. Old Meteorite packages got mrt: prefix - couple of words on that later.

There are two rules regarding the packages:

Package Rule Number One

Always check how up-to-date the package is. Even though it may seem tempting to just type meteor add joe:another-cool-bootstrap3-support, you’re risking installing a really outdated version that can cause your program to function weirdly. Even worse, it may seem to work just fine, but later you can come across strange problems with a very little chance of pinpointing the source. Especially be careful with packages prefixed mrt: Usually, there are out-of-date, and were not upgraded since Meteorite times.

There is an easy way to get information about package’s maintainer and repository. Just type meteor show package and at the bottom there will be a link, such as “Maintained by pinglamb at https://github.com/pinglamb/meteor-bootstrap3.git”

Package Rule Number Two

You don’t really need most of the packages.

Take Bootstrap support, for example. There are lots of packages available that do nothing more, than wrapping the latest version of Bootstrap framework - or the version that was the latest when they this package was created - into some simple Meteor packaging metadata.

Your mileage may vary, but I found it to be easier and better to include all external dependencies to the project’s lib/ folder instead. This way you have a full control of 3rd party software that goes into your project, and you can also set the order by which external .js files are loaded - more on that later.

Meteor Directory Structure

Meteor is one of the most permissive frameworks I’ve ever seen when it comes to structuring your project. There are many different approaches to be found on the Internets, but I’d like to share one that worked for me the best. But before that, there are several facts about how Meteor loads project files:

  • First, it loads model.js  file that sits in the project root. It has code that is shared between a server and a client. More on that is here.

  • Second, it loads server/server.js file.

  • Then it loads all .js and .css files from client/lib folder. As you can guess, it’s all 3rd-party client-related stuff, such as Bootstrap or Leaflet.js.

  • And then it loads everything else from client/ folder.

  • The public/ folder is exposed to the web project root (/), and usually has images, fonts, and maybe some other static content.

More wordy and detailed explanation from Meteor’s creators is available here.

Having that all in mind, I structure my projects like this:

.
├── client
│   ├── app
│   │   ├── dashboard
│   │   │   ├── dashboard.jade
│   │   │   ├── dashboard.js
│   │   │   ├── map.jade
│   │   │   └── map.js
│   │   ├── index
│   │   │   ├── 404.jade
│   │   │   ├── index.jade
│   │   │   ├── index.js
│   │   │   ├── navbar.jade
│   │   │   ├── navbar.js
│   │   │   ├── sidebar.jade
│   │   │   └── sidebar.js
│   │   ├── login
│   │   │   ├── login.jade
│   │   │   └── login.js
│   ├── lib
│   │   ├── css
│   │   │   ├── _1bootstrap.min.css
│   │   │   ├── bootstrap-editable.css
│   │   │   └── leaflet.css
│   │   └── js
│   │       ├── _1bootstrap.min.js
│   │       ├── _7bootstrap-editable.min.js
│   │       └── _8leaflet.js
│   └── styles
│       └── main.css
├── model.js
├── public
│   ├── fonts
│   │   ├── FontAwesome.otf
│   │   ├── fontawesome-webfont.eot
│   │   ├── fontawesome-webfont.svg
│   │   ├── fontawesome-webfont.ttf
│   │   ├── fontawesome-webfont.woff
│   │   ├── glyphicons-halflings-regular.eot
│   │   ├── glyphicons-halflings-regular.svg
│   │   ├── glyphicons-halflings-regular.ttf
│   │   └── glyphicons-halflings-regular.woff
│   └── img
│       ├── marker-icon-2x.png
│       ├── marker-icon-red-2x.png
│       ├── marker-icon.png
│       ├── marker-shadow.png
│       ├── profile-pic.jpg
│       └── user.jpg
└── server
    └── server.js

By doing that I have my client views and controllers in the same place, I have my 3rd party libraries isolated, and I have my public folder clean.

3rd-party Libs Load Order

As I mentioned before, it’s very important to know what you load first, and what you load last in your app. Doing it incorrectly will result in all kind of problems, from Bootstrap components not working correctly, to intermittent Leaflet.js crashes, to some other weird problems.

Unfortunately, the only way to change libraries loading order is a good old tried renaming. Files starting with ‘a’ will be loaded before files with ‘z’. I ended up adding numbers to my libs like that:

_1bootstrap.min.js
_2ace.min.js
_3ace-extra.min.js
_4tinycolor.js
_5jquery.easypiechart.min.js
_6bootstrap-editable.min.js
_7leaflet.js
_8fullcalendar.min.js

How do you know in which order to load libs? Just use your common sense and see what is needed first, and what is needed last. Kind of a manual “dependency resolution.”

Meteor Routing

By default, Meteor works with just a single URL. If you want to have something a little bit more - and if you’re writing a more or less sophisticated app - I bet you would, then you should use Iron Router.

Basically, it’s a very straightforward routing system for Meteor. Here is an example from the real app, so you can see how powerful and self-explanatory it is:

// Default routing settings
Router.configure({
  layoutTemplate: 'index',
  notFoundTemplate: '404'
});

// Show login screen unless signed in
Router.onBeforeAction(function(pause) {
  if (! Meteor.userId()) {
    this.setLayout(null);
    this.render('login');
    pause();
  } else {
    this.setLayout(this.lookupLayoutTemplate());
  }
});

// Routes
routes = {
  'dashboard':  { name: 'Dashboard', description: 'overview & stats', path: '/' },
  'devices':    { name: 'Devices', description: 'device list' },
  'scheduling': { name: 'Scheduling', description: 'on/off scheduling calendar' },
  'alarms':     { name: 'Alarms', description: 'device alarms' },
  'messages':   { name: 'Messages', description: 'messages from the system' },

  'deviceView': {
    name: 'Device details',
    description: 'device historical data & details',
    path: 'devices/:_id',
    data: function() { return Devices.findOne(this.params._id); }
  }
};

Router.map(function() {
  _.each(routes, function(route, url) {
    Router.route(url, { path: route.path, data: route.data });
  });
};

Here I have a default layout ‘index’, a 404 page, and ‘login’ template. ‘dashboard’, ‘devices’, ‘scheduling’, etc are the names of templates.

That’s it. Please just drop me a line if it was helpful, or if you have any questions. I’m in the comments all the time.