How I develop MeteorJS apps

What this article is about

In this article I will show you my way of setting up apps written in MeteorJS. And how this helps me avoiding problems when the app grows.

I have divided the article into three parts:

How I develop MeteorJS apps - part 1. Package for everything

But start with the issues

These are the issues I encountered when building various Meteor apps:

Tests slow down development

I have noticed that when the app grows, velocity tests are gradually slowing down each app refresh - in the end, tests run each time you change a file. My temporary solution was to turn off velocity during the development phase (VELOCITY=0 meteor) and run tests once in a while just to check code integrity.

Load order

Meteor has different rules defining in which order files are loaded. And this is not really a problem - you have to follow them and everything will be OK. But when your app starts to put on more and more weight you will definitely find yourself creating nested (normally not needed) folders just to ensure proper loading order - does client/lib/lib/main.js sound familiar?

Different programmers - different structures

Meteor only gives you an overall, basic set of rules how to structure your app (and in the beginning this is mind-blowing - just 3 files in a new app).
If you, just like me, often inherit projects from other developers you will end up learning the structure each time you start working on a different project.

Solution

The one and only solution to those problems I have found is a so-called “packages for everything” structure. It basically means that for every feature there is a dedicated package in your ./packages folder.

THE END.

….just kidding.

Package for everything

Let’s say you have to implement a new feature - in your app root run:

meteor create --package yourappname:featurename

and then immediately add this package to your app:

meteor add yourappname:featurename

Now in your new package in package.js define dependencies (api.use) add files (api.addFiles) and expose your API to the app (api.export). Each change in the added files will result in an automatic app update, like it was the case with every other file.

I often automatically create [/client, /server, /both, /i18n, /tests] folders in a newly created package to structure each package the same way I set up my apps.

How “package for everything” helps with the above issues

And this is how it helps me:

  1. tests are run per package (more about this later)
  2. load order is defined only by package.json
  3. when you have to add a new feature in a project which was developed by someone else, just create a new package

plus:

  1. main app namespace is clean - “package for everything” will force you to keep the global namespace clean
  2. you will see relations between different parts of your application, which can help you better design your app
  3. some of the packages you create this way could be published in Atmosphere and you can taste the fame of a rockstar MeteorJS programmer.

Things you have to know about packages

Every new package is a “tabula rasa”

It means that no dependency is loaded by default. So if your package uses ReactiveVar you have to include it in package.js (api.use(‘reactive-var’)). OK - that was obvious,wasn’t it?

But if you are going to add .html templates to your package - api.addFiles(“client/filename.html”) is not enough. You have to include “templating” and “blaze” to parse them and render respectively.

Defining dependency version is important

In your package.js when you include dependency you can explicitly define their version: e.g. api.use(‘aldeed:autoform@4.0.0 || 5.0.0’). I noticed that when you omit the version Meteor will not necessary use the latest one. This can cause strange, hard to debug issues. So if the loaded library is not working as expected - missing version in api.use() is the first place to check.

BTW: if you publish your packages on Atmosphere you have to explicitly define version, otherwise the package will not be published.

Packages have their own namespace

In order to expose data to your app from the package you have to use api.export on variables defined without “var”. But when you use coffeescript instead of javascript each of your files is wrapped in an anonymous function after compilation. This process “hides” all variables (api.export won’t work for them). To overcome this just create exports.js file with the following content:

ExportVar = this.ExportVar

add this file to package.js before other files: api.addFiles('exports.js') and export ExportVar: api.export(“ExportVar”). Then you will be able to use ExportVar in your coffeescripts.

ExportVar = {someImportant: ‘value’}

Package for (almost) everything

Things you should NOT put in a separate package:

Routes

Routes are the very first things I look for when joining a new MeteorJS project team. They can show a new developer how things perform from a wide angle. When you hide your routes inside packages newcomers will have problems finding the main map of your application and as a result they will spend more time understanding the app.

Credentials

Some of your packages will have to use secret keys to external services. My approach is to always put them in the app setting file and load credentials from there.

Each package which relies on data from Meteor.settings namespace can be documented in its readme.md file (each package can have its own readme file - isn’t that awesome?!).

Publications

Mostly, I place my publications in the main app, not in the packages for two important reasons:

  • they rely on different packages - usually I publish different collections and their relations
  • since they define what data we send from our secure server to the clients, I like to keep them in one place.

(Package for) Everything vs Almost Everything

Of course you can put all routes and publications in two separate packages and this will be OK. But this is my article ;] and I wanted to explain how I do this.

Summary

I hope that I have convinced you to try out the “package for everything” approach because... it is just awesome.

Not convinced yet? - wait for my next article about testing packages.
Subscribe of follow me @wojtek_krysiak and don't miss anything.

#meteor
Wojciech Krysiak
CTO and co-founder of RST-IT. Technology enthusiast with a passion for coding. Wojtek is a charismatic Team Leader, who never allows anyone in the team to lose energy