Meteor released version 0.9 this week and everyone is busy migrating their apps and packages. So, I am not going to talk about things we already know. But this is a story, which no one has told before :)
Before we begin, we need to understand why Meteor released a packaging system and how it differs from Meteorite.
Meteorite is tightly coupled to Git, it’s not baked into the Meteor core and it does not support weak dependencies. These are some of the few things the new packaging system solves. But, versioning support is the heart of the new packaging system and a lot of decisions have been taken around that.
Meteor uses semver as the backbone of its versioning support. But unlike npm (which also uses semver), the Meteor packaging system only allows a single version of a package to live inside an app. No matter what your app’s dependency tree is, Meteor will resolve all packages into a single version or it throws an error.
Semver is short for “semantic versioning”. It’s a guideline for how to version your packages. It’s pretty simple. Let’s see.
Basically, there are three numbers for a version:
This is what they mean:
Semver has some other features, but now you know more than enough semver to continue with our story.
Say there are a couple of packages, like below, in the Meteor packaging repository (not inside your app):
Now, let’s say you have added
gadi:bar into your app with:
meteor add gadi:bar
If you look at the
.meteor/versions file, you can see the following versions from the above two packages:
Some time later, you want to use
arunoda:foo directly in you app. But you want to use version 1.4.0. You type:
meteor add arunoda:firstname.lastname@example.org
Now if you look at the
.meteor/version file, you will have the following versions:
gadi:bar asked for
arunoda:foo at version 1.0.0, right?
gadi:bar mentioned that 1.0.0 is the minimum version that it depends on for
arunoda:foo. According to semver, minor releases must be backward compatible. Since 1.4.0 is a minor release compared with 1.0.0,
gadi:bar should work with
arunoda:foo is a really cool project and there is a lot of development going on.
arunoda:email@example.com is the latest release and you want to use it in your app.
meteor add arunoda:firstname.lastname@example.org
But your apps will fail with a message like this:
conflict: arunoda:email@example.com vs arunoda:foo2.0.0
arunoda:firstname.lastname@example.org is a major release compared with
arunoda:email@example.com, which already exists in our app. So,
gadi:bar can’t work with
arunoda:firstname.lastname@example.org according to semver. That’s why Meteor throws an error.
Now, you can either remove
gadi:bar or ask Gadi to update the package for
You must stick to semver.
Because of the tight integration with semver, package authors must follow semver strictly. If not, they could break the packaging system. Let’s see some cases.
Version Playground is a little tool where you can experiment with new packaging systems and learn how versioning works.
It’s backed by the same packages Meteor uses to resolve dependencies. So it’s very similar to how the actual packaging system works. Visit the version playground: http://version-playground.meteor.com/
See how we can use it:
Now, here’s the fun part. We are going to break the packaging system and you will learn how it happened. Then you can take action to prevent such scenarios.
Okay, let’s begin.
Semver is new to some package developers. Previously, I also didn’t follow it. If you don’t follow semver, you might be the person who breaks the packaging system. See how:
arunoda:email@example.com, you are specifying 1.0.0 as the minimum version. But you can ask for exactly version 1.0.0:
This seems like a nice feature! But this is another way to break the packaging system:
Your package development is going super fast. So, you might start releasing new major versions too often. But they are still backward compatible.
In a situation like this, all the packages depending on your package also need to be updated for your major releases. Which is very hard to do in practice, unless you send Pull Requests to all those packages.
If this doesn’t happen, your newest releases won’t be used with these apps.
I try to follow these guidelines for my packages:
When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. Example: 1.0.0-alpha < 1.0.0. Precedence for two pre-release versions with the same major, minor, and patch version MUST be determined by comparing each dot separated identifier from left to right until a difference is found as follows: identifiers consisting of only digits are compared numerically and identifiers with letters or hyphens are compared lexically in ASCII sort order. Numeric identifiers always have lower precedence than non-numeric identifiers. A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
That’s the story for today :)
I hope you’ve enjoyed it. Now it’s time to take some action. Start building packages and apps for the Meteor packaging system without breaking it :)
Note: All of our packages are available under the meteorhacks namespace.