To get started writing a package, use the Meteor command line tool:
It is required that your
my-packagename take the form of
usernameis your Meteor Developer username, if you plan to publish your package to Atmosphere.
If you run this inside an app, it will place the newly generated package in that app’s
packages/ directory. Outside an app, it will just create a standalone package directory. The command also generates some boilerplate files for you:
In this guide article, we will go over some important points for building packages, but we won’t explain every part of the
package.js API. To learn about all of the options, read about the
package.js API in the Meteor docs.
Don’t forget to run
meteor add [my-package]once you have finished developing your package in order to use it; this applies if the package is a local package for internal use only or if you have published the package to Atmosphere.
Adding files and assets
The main function of an Atmosphere package is to contain source code (JS, CSS, and any transpiled languages) and assets (images, fonts, and more) that will be shared across different applications.
api.mainModule() in the package’s
onUse block (this will already have been done by
meteor create --package above):
From that entrypoint, you can
import other files within your package, just as you would in an application.
If you want to include different files on the client and server, you can specify multiple entry points using the second argument to the function:
You can also add any source file that would be compiled to a JS file (such as a CoffeeScript file) in a similar way, assuming you depend on an appropriate build plugin.
To include CSS files with your package you can use
The CSS file will be automatically loaded into any app that uses your package.
Adding Sass, Less, or Stylus mixins/variables
This Sass file will be eagerly evaluated and its compiled form will be added to the CSS of the app immediately.
These two Sass files will be lazily evaluated and only included in the CSS of the app if imported from some other file.
Adding other assets
You can include other assets, such as fonts, icons or images, to your package using
You can then access these files from the client from a URL
/packages/username_my-package/font/OpenSans-Regular-webfont.eot or from the server using the Assets API.
While some packages exist just to provide side effects to the app, most packages provide a reusable bit of code that can be used by the consumer with
import. To export a symbol from your package, simply use the ES2015
export syntax in your
Now users of your package can import the symbol with:
Chances are your package will want to make use of other packages. To ensure they are available, you can declare dependencies. Atmosphere packages can depend both on other Atmosphere packages, as well as packages from npm.
To depend on another Atmosphere package, use
One important feature of the Atmosphere package system is that it is single-loading: no two packages in the same app can have dependencies on conflicting versions of a single package. Read more about that in the section about version constraints below.
Depending on Meteor version
Note that the Meteor release version number is mostly a marketing artifact - the core Meteor packages themselves typically don’t share this version number. This means packages can only depend on specific versions of the packages inside a Meteor release, but can’t depend on a specific release itself. We have a helpful shorthand api called
api.versionsFrom that handles this for you by automatically filling in package version numbers from a particular release:
The above code snippet is equivalent to the code below, which specifies all of the version numbers individually:
Semantic versioning and version constraints
Meteor’s package system relies heavily on Semantic Versioning, or SemVer. When one package declares a dependency on another, it always comes with a version constraint. These version constraints are then solved by Meteor’s industrial-grade Version Solver to arrive at a set of package versions that meet all of the requirements, or display a helpful error if there is no solution.
The mental model here is:
- The major version must always match exactly. If package
firstname.lastname@example.org, the constraint will only be satisfied if the version of package
bstarts with a
2. This means that you can never have two different major versions of a package in the same app.
- The minor and patch version numbers must be greater or equal to the requested version. If the dependency requests version
2.2.0will work, but
The constraint solver is necessary because Meteor’s package system is single-loading - that is, you can never have two different versions of the same package loaded side-by-side in the same app. This is particularly useful for packages that include a lot of client-side code, or packages that expect to be singletons.
Note that the version solver also has a concept of “gravity” - when many solutions are possible for a certain set of dependencies, it always selects the oldest possible version. This is helpful if you are trying to develop a package to ship to lots of users, since it ensures your package will be compatible with the lowest common denominator of a dependency. If your package needs a newer version than is currently being selected for a certain dependency, you need to update your
package.js to have a newer version constraint.
package.js file. For example, here’s how you would include the
github npm package:
You can import the dependency from within you package code in the same way that you would inside an application:
Peer npm dependencies
Npm.depends() is fairly rigid (you can only depend on an exact version), and will typically result in multiple versions of a package being installed if many different Atmosphere packages depend on the same npm package. This makes it less than ideal to use on the client, where it’s impractical to ship multiple copies of the same package code to the browser. Client-side packages are also often written with the assumption that only a single copy will be loaded. For example, React will complain if it is included more than once in an application bundle.
To avoid this problem as a package author, you can request that users of your package have installed the npm package you want to use at the application level. This is similar to a peer dependency of an npm package (although with less support in the tool). You can use the
tmeasday:check-npm-versions package to ensure that they’ve done this, and to warn them if not.
For instance, if you are writing a React package, you should not directly depend on
react, but instead use
check-npm-versions to check the user has installed it:
checkNpmVersionswill only output a warning if the user has installed a incompatible version of the npm package. So your
requirecall may not give you what you expect. This is consistent with npm’s handling of peer dependencies.
Atmosphere packages can include Cordova plugins to ship native code for the Meteor mobile app container. This way, you can interact with the native camera interface, use the gyroscope, save files locally, and more.
Include Cordova plugins in your Meteor package by using Cordova.depends.
Read more about using Cordova in the mobile guide.
Meteor has a test mode for packages called
meteor test-packages. If you are in a package’s directory, you can run
This will run a special app containing only a “test” version of your package and start a Mocha test driver package.
When your package starts in test mode, rather than loading the
onUse block, Meteor loads the
From within your test entry point, you can import other files as you would in the package proper.
You can read more about testing in Meteor in the Testing article.
Publishing your package
To publish your package to Atmosphere, run
meteor publish from the package directory. To publish a package the package name must follow the format of
username:my-package and the package must contain a SemVer version number.
If you’ve ever looked inside Meteor’s package cache at
~/.meteor/packages, you know that the on-disk format of a built Meteor package is completely different from the way the source code looks when you’re developing the package. The idea is that the target format of a package can remain consistent even if the API for development changes.
As an alternative to publishing your package on Atmosphere, if you want to keep your package private, you can place it in your Meteor app in the
packages/ directory, for instance
packages/foo/, and then add it to your app with
meteor add foo.
Overriding published packages with a local version
If you need to modify an Atmosphere package to do something that the published version doesn’t do, you can edit a local version of the package on your computer.
A Meteor app can load Atmosphere packages in one of three ways, and it looks for a matching package name in the following order:
- Package source code in the
packages/directory inside your app.
- Package source code in directories indicated by setting a
METEOR_PACKAGE_DIRSenvironment variable before running any
meteorcommand. You can add multiple directories by separating the paths with a
:on OSX or Linux, or a
;on Windows. For example:
METEOR_PACKAGE_DIRS=../first/directory:../second/directory, or on Windows:
Note: Prior to Meteor 1.4.2,
PACKAGE_DIRS. For compatibility reasons, developers should use
- Pre-built package from Atmosphere. The package is cached in
~/.meteor/packageson Mac/Linux or
%LOCALAPPDATA%\.meteor\packageson Windows, and only loaded into your app as it is built.
You can use (1) or (2) to override the version from Atmosphere. You can even do this to load patched versions of Meteor core packages - just copy the code of the package from Meteor’s GitHub repository, and edit away.