Package.js

Documentation of Meteor's package API.

A package is a directory containing a package.js file, whichcontains roughly three major sections: a basic description, a packagedefinition, and a test definition. By default, the directory name is the name ofthe package.

The package.js file below is an example of how to use the packaging API. Therest of this section will explain the specific API commands in greater detail.

  1. // Information about this package:
  2. Package.describe({
  3. // Short two-sentence summary
  4. summary: 'What this does',
  5. // Version number
  6. version: '1.0.0',
  7. // Optional, default is package directory name
  8. name: 'username:package-name',
  9. // Optional GitHub URL to your source repository
  10. git: 'https://github.com/something/something.git'
  11. });
  12. // This defines your actual package:
  13. Package.onUse((api) => {
  14. // If no version is specified for an `api.use` dependency, use the one defined
  15. // in Meteor 1.4.3.1.
  16. api.versionsFrom('1.4.3.1');
  17. // Use the `underscore` package, but only on the server. Version not
  18. // specified, so it will be as of Meteor 1.4.3.1.
  19. api.use('underscore', 'server');
  20. // Use `kadira:flow-router`, version 2.12.1 or newer.
  21. api.use('kadira:flow-router@2.12.1');
  22. // Give users of this package access to active-route's JavaScript helpers.
  23. api.imply('zimme:active-route@2.3.2')
  24. // Export the object `Email` to packages or apps that use this package.
  25. api.export('Email', 'server');
  26. // Specify the source code for the package.
  27. api.addFiles('email.js', 'server');
  28. // When using `ecmascript` or `modules` packages, you can use this instead of
  29. // `api.export` and `api.addFiles`.
  30. api.mainModule('email.js', 'server');
  31. });
  32. // This defines the tests for the package:
  33. Package.onTest((api) => {
  34. // Sets up a dependency on this package.
  35. api.use('username:package-name');
  36. // Use the Mocha test framework.
  37. api.use('practicalmeteor:mocha@2.4.5_2');
  38. // Specify the source code for the package tests.
  39. api.addFiles('email_tests.js', 'server');
  40. });
  41. // This lets you use npm packages in your package:
  42. Npm.depends({
  43. simplesmtp: '0.3.10',
  44. 'stream-buffers': '0.2.5'
  45. });

api.mainModule is documented in the modules section.

Build plugins are created withPackage.registerBuildPlugin. See thecoffeescript package for an example. Build plugins are fully-fledged Meteorprograms in their own right and have their own namespace, package dependencies,source files and npm requirements.

You can use local packages to define custom build pluginsfor your app, with one caveat. In published packages, build plugins are alreadybundled with their transitive dependencies. So if you want a dependency of abuild plugin to be satisfied by a local package, you must use a local copy ofthe package that defines the plugin (even if you make no changes to thatpackage) so that Meteor will pick up the local dependency.

Provide basic package information with Package.describe(options). To publish apackage, you must define summary and version.

package.js

Package.describe(options)

Provide basic package information.

Options

  • summaryString
  • A concise 1-2 sentence description ofthe package, required for publication.

  • versionString

  • The (extended)semver version for your package. Additionally,Meteor allows a wrap number: a positive integer that follows theversion number. If you are porting another package that uses semverversioning, you may want to use the original version, postfixed with_wrapnumber. For example, 1.2.3_1 or 2.4.5-rc1_4. Wrap numberssort after the original numbers: 1.2.3 < 1.2.3_1 < 1.2.3_2 <1.2.4-rc.0. If no version is specified, this field defaults to0.0.0. If you want to publish your package to the package server, youmust specify a version.

  • nameString

  • Optional name override. By default, thepackage name comes from the name of its directory.

  • gitString

  • Optional Git URL to the source repository.

  • documentationString

  • Optional Filepath todocumentation. Set to 'README.md' by default. Set this to null to submitno documentation.

  • debugOnlyBoolean

  • A package with this flag set to truewill not be bundled into production builds. This is useful for packagesmeant to be used in development only.

  • prodOnlyBoolean

  • A package with this flag set to truewill ONLY be bundled into production builds.

  • testOnlyBoolean

  • A package with this flag set to truewill ONLY be bundled as part of meteor test.

Define dependencies and expose package methods with thePackage.onUse handler. This section lets you define what packages your packagedepends on, what packages are implied by your package, and what object yourpackage is exported to.

package.js

Package.onUse(func)

Define package dependencies and expose package methods.

Arguments

  • funcFunction
  • A function that takes in the package control api object, which keeps track of dependencies and exports.

package.js

api.versionsFrom(meteorRelease)

Use versions of core packages from a release. Unless provided,all packages will default to the versions released along withmeteorRelease. This will save you from having to figure out the exactversions of the core packages you want to use. For example, if the newestrelease of meteor is `METEOR@0.9.0and it includesjquery@1.0.0, youcan writeapi.versionsFrom('METEOR@0.9.0')in your package, and when youlater writeapi.use('jquery'), it will be equivalent toapi.use('jquery@1.0.0'). You may specify an array of multiple releases,in which case the default value for constraints will be the "or" of theversions from each release:api.versionsFrom(['METEOR@0.9.0','METEOR@0.9.5'])may causeapi.use('jquery')to be interpreted asapi.use('jquery@1.0.0 || 2.0.0')`.

Arguments

  • meteorReleaseString or Array of Strings
  • Specification of a release:track@version. Just 'version' (e.g. "0.9.0") is sufficient if using thedefault release track METEOR. Can be an array of specifications.

package.js

api.use(packageNames, [architecture], [options])

Depend on package packagename.

Arguments

  • packageNamesString or Array of Strings
  • Packages being depended on.Package names may be suffixed with an @version tag.

In general, you must specify a package's version (e.g.,`'accounts@1.0.0'to use version 1.0.0 or a highercompatible version (ex: 1.0.1, 1.5.0, etc.) of theaccountspackage). If you are sourcing corepackages from a Meteor release withversionsFrom, you may leaveoff version names for core packages. You may also specify constraints,such asmy:forms@=1.0.0(this package demandsmy:formsat1.0.0exactly),ormy:forms@1.0.0 || =2.0.1(my:formsat1.x.y, or exactly2.0.1`).

  • architectureString or Array of Strings
  • If you only use the package on theserver (or the client), you can pass in the second argument (e.g.,'server', 'client', 'web.browser', 'web.cordova') to specifywhat architecture the package is used with. You can specify multiplearchitectures by passing in an array, for example ['web.cordova', 'os.linux'].

Options

  • weakBoolean
  • Establish a weak dependency on apackage. If package A has a weak dependency on package B, it meansthat including A in an app does not force B to be included too — but,if B is included or by another package, then B will load before A.You can use this to make packages that optionally integrate with orenhance other packages if those packages are present.When you weakly depend on a package you don't see its exports.You can detect if the possibly-present weakly-depended-on packageis there by seeing if Package.foo exists, and get its exportsfrom the same place.

  • unorderedBoolean

  • It's okay to load this dependencyafter your package. (In general, dependencies specified by api.useare loaded before your package.) You can use this option to breakcircular dependencies.

package.js

api.imply(packageNames, [architecture])

Give users of this package access to another package (by passingin the string packagename) or a collection of packages (by passing inan array of strings [packagename1, packagename2]

Arguments

  • packageNamesString or Array of Strings
  • Name of a package, or array ofpackage names, with an optional @version component for each.

  • architectureString or Array of Strings

  • If you only use the package onthe server (or the client), you can pass in the second argument (e.g.,'server', 'client', 'web.browser', 'web.cordova') to specify whatarchitecture the package is used with. You can specify multiplearchitectures by passing in an array, for example ['web.cordova','os.linux'].

package.js

api.export(exportedObjects, [architecture], [exportOptions], exportOptions.testOnly)

Export package-level variables in your package. The specifiedvariables (declared without var in the source code) will be availableto packages that use your package. If your package sets the debugOnly,prodOnly or testOnly options to true when it callsPackage.describe(), then packages that use your package will need to usePackage["package-name"].ExportedVariableName to access the value of anexported variable.

Arguments

  • exportedObjectsString or Array of Strings
  • Name of the object to export, oran array of object names.

  • architectureString or Array of Strings

  • If you only want to export theobject on the server (or the client), you can pass in the second argument(e.g., 'server', 'client', 'web.browser', 'web.cordova') to specify whatarchitecture the export is used with. You can specify multiplearchitectures by passing in an array, for example ['web.cordova','os.linux'].

  • exportOptionsObject

  • exportOptions.testOnlyBoolean
  • If true, this symbol will only beexported when running tests for this package.

package.js

api.addFiles(filenames, [architecture], [options])

Specify source code files for your package.

Arguments

  • filenamesString or Array of Strings
  • Paths to the source files.

  • architectureString or Array of Strings

  • If you only want to use the fileon the server (or the client), you can pass this argument(e.g., 'server', 'client', 'web.browser', 'web.cordova') to specifywhat architecture the file is used with. You can specify multiplearchitectures by passing in an array, for example['web.cordova', 'os.linux']. By default, the file will be loaded on bothserver and client.

Options

  • bareBoolean
  • If this file is JavaScript code or willbe compiled into JavaScript code by a build plugin, don't wrap theresulting file in a closure. Has the same effect as putting a file into theclient/compatibility directory in an app.

package.js

api.addAssets(filenames, architecture)

Specify asset files for your package. They can be accessed viathe Assets API from the server, or at the URL/packages/username_package-name/file-name from the client, depending on thearchitecture passed.

Arguments

  • filenamesString or Array of Strings
  • Paths to the asset files.

  • architectureString or Array of Strings

  • Specify where this asset should beavailable (e.g., 'server', 'client', 'web.browser', 'web.cordova'). You canspecify multiple architectures by passing in an array, for example['web.cordova', 'os.linux'].

Set up your tests with the Package.onTest handler, which has an interfacethat’s parallel to that of the onUse handler. The tests will need to depend onthe package that you have just created. For example, if your package is theemail package, you have to call api.use('email') in order to test thepackage.

If you used meteor create to set up your package, Meteor will create therequired scaffolding in package.js, and you’ll only need to add unit test codein the _test.js file that was created.

package.js

Package.onTest(func)

Define dependencies and expose package methods for unit tests.

Arguments

  • funcFunction
  • A function that takes in the package control 'api' object, which keeps track of dependencies and exports.

Meteor packages can include NPM packages and Cordova plugins by usingNpm.depends and Cordova.depends in the package.js file.

package.js

Npm.depends(dependencies)

Specify which NPM packagesyour Meteor package depends on.

Arguments

  • dependenciesObject
  • An object where the keys are packagenames and the values are one of:

    • Version numbers in string form
    • http(s) URLs of npm packages
    • Git URLs in the format described hereHttps URL example:
  1. Npm.depends({
  2. moment: "2.8.3",
  3. async: "https://github.com/caolan/async/archive/71fa2638973dafd8761fa5457c472a312cc820fe.tar.gz"
  4. });

Git URL example:

  1. Npm.depends({
  2. moment: "2.8.3",
  3. async: "git+https://github.com/caolan/async#master"
  4. });

Server

Npm.require

Require a package that was specified usingNpm.depends().

Arguments

  • nameString
  • The name of the package to require.

package.js

Cordova.depends(dependencies)

Specify which Cordova / PhoneGapplugins your Meteor package depends on.

Plugins are installed fromplugins.cordova.io, so the plugins andversions specified must exist there. Alternatively, the versioncan be replaced with a GitHub tarball URL as described in theCordovapage of the Meteor wiki on GitHub.

Arguments

  • dependenciesObject
  • An object where the keys are pluginnames and the values are version numbers or GitHub tarball URLsin string form.Example:
  1. Cordova.depends({
  2. "org.apache.cordova.camera": "0.3.0"
  3. });

Alternatively, with a GitHub URL:

  1. Cordova.depends({
  2. "org.apache.cordova.camera":
  3. "https://github.com/apache/cordova-plugin-camera/tarball/d84b875c449d68937520a1b352e09f6d39044fbf"
  4. });

package.js

Package.registerBuildPlugin([options])

Define a build plugin. A build plugin extends the buildprocess for apps and packages that use this package. For example,the coffeescript package uses a build plugin to compile CoffeeScriptsource files into JavaScript.

Options

  • nameString
  • A cosmetic name, must be unique in thepackage.

  • useString or Array of Strings

  • Meteor packages that thisplugin uses, independent of the packages specified inapi.onUse.

  • sourcesArray of Strings

  • The source files that make up thebuild plugin, independent from api.addFiles.

  • npmDependenciesObject

  • An object where the keysare NPM package names, and the values are the version numbers ofrequired NPM packages, just like in Npm.depends.

Build Plugin

Plugin.registerSourceHandler(fileExtension, handler)

Inside a build plugin source file specified inPackage.registerBuildPlugin,add a handler to compile files with a certain file extension.

Arguments

  • fileExtensionString
  • The file extension that this pluginshould handle, without the first dot.Examples: "coffee", "coffee.md".

  • handlerFunction

  • A function that takes one argument,a CompileStep object.

Documentation for CompileStep is available on the GitHub Wiki.

Build Plugins API

Meteor packages can provide build plugins - programs that integrate with thebuild tool Isobuild used to compile and bundle your application.

Starting with Meteor 1.2, the API used to plug into the build process is called“Build Plugins”. There are 3 phases when a package’s plugin can run: linting,compilation and minification. Here is an overview of operations Isobuildperforms on the application and packages source:

  • Gather source files from the app folder or read package.js file for apackage.
  • Lint all source files and print the linting warnings.
  • Compile the source files like CoffeeScript, ES2015, Less, or Templates to plainJavaScript and CSS.
  • Link the JavaScript files: wrap them into closures and provide necessarypackage imports.
  • Minify JavaScript and CSS files. Can also include concatenation of all files.Build plugins fill the phases 2, 3 and 5.

Usually build plugins implement a class that is given a list of files toprocess. Commonly, such files have the following methods:

  • getContentsAsBuffer - Returns the full contents of the file as a buffer.
  • getContentsAsString - Returns the full contents of the file as a string.
  • getPackageName - Returns the name of the package or null if the file is not in a package.
  • getPathInPackage - Returns the relative path of file to the package or app root directory. The returned path always uses forward slashes.
  • getSourceHash - Returns a hash string for the file that can be used to implement caching.
  • getArch - Returns the architecture that is targeted while processing this file.
  • getBasename - Returns the filename of the file.
  • getDirname - Returns the directory path relative to the package or app root. The returned path always uses forward slashes.
  • error - Call this method to raise a compilation or linting error for the file.

Linters

Linters are programs that check the code for undeclared variables or find codethat doesn’t correspond to certain style guidelines. Some of the popularexamples of linters are JSHint andESLint. Some of the non-JavaScript linter examples includeCoffeeLint for CoffeeScript andCSSLint for CSS.

To register a linter build plugin in your package, you need to do a couple ofthings in your package.js:

  • depend on the isobuild:linter-plugin@1.0.0 package
  • register a build plugin: Package.registerBuildPlugin({ name, sources, … });(see docs)

In your build plugin sources, register a Linter Plugin: provide details such asa name, list of extensions and filenames the plugin will handle and a factoryfunction that returns an instance of a linter class. Example:

  1. Plugin.registerLinter({
  2. extensions: ['js'],
  3. filenames: ['.linterrc']
  4. }, () => new MyLinter);

In this example, we register a linter that runs on all js files and also readsa file named .linterrc to get a configuration.

The MyLinter class should now implement the processFilesForPackagemethod. The method should accept two arguments: a list of files and an optionsobject.

  1. class MyLinter {
  2. processFilesForPackage(files, options) {
  3. files.forEach((file) => {
  4. // Lint the file.
  5. const lint = lintFile(file.getContentsAsString());
  6. if (lint) {
  7. // If there are linting errors, output them.
  8. const { message, line, column } = lint;
  9. file.error({ message, line, column });
  10. }
  11. });
  12. }
  13. }

The globals are passed in the options object so that the linters can omit thewarnings about the package imports that look like global variables.

Each file in the list is an object that has all the methods provided by allbuild plugins, described above.

See an example of a linting plugin implemented in Core: jshint.

Compilers

Compilers are programs that take the source files and output JavaScript orCSS. They also can output parts of HTML that is added to the <head> tag andstatic assets. Examples for the compiler plugins are: CoffeeScript, Babel.js,JSX compilers, Pug templating compiler and others.

To register a compiler plugin in your package, you need to do the following inyour package.js file:

  • depend on the isobuild:compiler-plugin@1.0.0 package
  • register a build plugin: Package.registerBuildPlugin({ name, sources, … });(see docs)

In your build plugin source, register a Compiler Plugin: similar to other typesof build plugins, provide the details, extensions and filenames and a factoryfunction that returns an instance of the compiler. Ex.:

  1. Plugin.registerCompiler({
  2. extensions: ['pug', 'tpl.pug'],
  3. filenames: []
  4. }, () => new PugCompiler);

The compiler class must implement the processFilesForTarget method that isgiven the source files for a target (server or client part of the package/app).

  1. class PugCompiler {
  2. processFilesForTarget(files) {
  3. files.forEach((file) => {
  4. // Process and add the output.
  5. const output = compilePug(file.getContentsAsString());
  6. file.addJavaScript({
  7. data: output,
  8. path: `${file.getPathInPackage()}.js`
  9. });
  10. });
  11. }
  12. }

Besides the common methods available on the input files’ class, the followingmethods are available:

  • getExtension - Returns the extension that matched the compiler plugin. Thelongest prefix is preferred.
  • getDeclaredExports - Returns a list of symbols declared as exports in thistarget. The result of api.export('symbol') calls in target’s control filesuch as package.js.
  • getDisplayPath Returns a relative path that can be used to form errormessages or other display properties. Can be used as an input to a source map.
  • addStylesheet - Web targets only. Add a stylesheet to the document. Notavailable for linter build plugins.
  • addJavaScript - Add JavaScript code. The code added will only see thenamespaces imported by this package as runtime dependencies using‘api.use’. If the file being compiled was added with thebare flag, the resulting JavaScript won’t be wrapped in a closure.
  • addAsset - Add a file to serve as-is to the browser or to include on thebrowser, depending on the target. On the web, it will be served at the exactpath requested. For server targets, it can be retrieved usingAssets.getText or Assets.getBinary.
  • addHtml - Works in web targets only. Add markup to the head or bodysection of the document.

Meteor implements a couple of compilers as Core packages, good examples would betheBlaze templatingpackage and theecmascriptpackage (compiles ES2015+ to JavaScript that can run in the browsers).

Minifiers

Minifiers run last after the sources has been compiled and JavaScript code hasbeen linked. Minifiers are only ran for the client programs (web.browser andweb.cordova).

There are two types of minifiers one can add: a minifier processing JavaScript(registered extensions: ['js']) and a minifier processing CSS (extensions:['css']).

To register a minifier plugin in your package, add the following in yourpackage.js file:

  • depend on isobuild:minifier-plugin@1.0.0 package
  • register a build plugin: Package.registerBuildPlugin({ name, sources, … });(see docs)

In your build plugin source, register a Minifier Plugin. Similar to Linter andCompiler plugin, specify the interested extensions (css or js). The factoryfunction returns an instance of the minifier class.

  1. Plugin.registerMinifier({
  2. extensions: ['js']
  3. }, () => new UglifyJsMinifier);

The minifier class must implement the method processFilesForBundle. The firstargument is a list of processed files and the options object specifies if theminifier is ran in production mode or development mode.

  1. class UglifyJsMinifier {
  2. processFilesForBundle(files, options) {
  3. const { minifyMode } = options;
  4. if (minifyMode === 'development') {
  5. // Don't minify in development.
  6. file.forEach((file) => {
  7. file.addJavaScript({
  8. data: file.getContentsAsBuffer(),
  9. sourceMap: file.getSourceMap(),
  10. path: file.getPathInBundle()
  11. });
  12. });
  13. return;
  14. }
  15. // Minify in production.
  16. files.forEach((file) => {
  17. file.addJavaScript({
  18. data: uglifyjs.minify(file.getContentsAsBuffer()),
  19. path: file.getPathInBundle()
  20. });
  21. });
  22. }
  23. }

In this example, we re-add the same files in the development mode to avoidunnecessary work and then we minify the files in production mode.

Besides the common input files’ methods, these methods are available:

  • getPathInBundle - returns a path of the processed file in the bundle.
  • getSourceMap - returns the source-map for the processed file if there is such.
  • addJavaScript - same as compilers
  • addStylesheet - same as compilers

Right now, Meteor Core ships with the standard-minifiers package that can bereplaced with a custom one. Thesourceof the package is a good example how to build your own minification plugin.

Caching

Since the API allows build plugins to process multiple files at once, we encourage package authors to implement at least some in-memory caching for their plugins. Using the getSourceHash function for linters and compilers will allow quick incremental recompilations if the file is not reprocessed even when the contents didn’t change.

For the fast rebuilds between the Isobuild process runs, plugins can implement on-disk caching. If a plugin implements the setDiskCacheDirectory method, it will be called from time to time with a new path on disk where the plugin can write its offline cache. The folder is correctly reset when the plugin is rebuilt or cache should be invalidated for any reason (for example, picked package versions set has changed).

Caching Compiler

There is a core package called caching-compiler that implements most of the common logic of keeping both in-memory and on-disk caches. The easiest way to implement caching correctly is to subclass the CachingCompiler or MultiFileCachingCompiler class from this package in your build plugin. CachingCompiler is for compilers that consider each file completely independently; MultiFileCachingCompiler is for compilers that allow files to reference each other. To get this class in your plugin namespace, add a dependency to the plugin definition:

  1. Package.registerBuildPlugin({
  2. name: 'compileGG',
  3. use: ['caching-compiler@1.0.0'],
  4. sources: ['plugin/compile-gg.js']
  5. });

Accessing File System

Since the build plugins run as part of the Meteor tool, they follow the same file-system access convention - all file system paths always look like a Unix path: using forward slashes and having a root at ‘/‘, even on Windows. For example: paths /usr/bin/program and /C/Program Files/Program/program.exe are valid paths, and C:\Program Files\Program\program.exe is not.

So whenever you get a path in your build plugin implementation, via getPathInPackage or in an argument of the setDiskCacheDirectory method, the path will be a Unix path.

Now, on running on Windows, the usual node modules fs and path expect to get a DOS path. To assist you to write correct code, the Plugin symbol provides its own versions of fs and path that you can use instead (note that all methods on fs are fiberized and sync versions prefer using Fibers rather than freezing the whole event loop).

Also Plugin provides helper functions convertToStandardPath and convertToOSPath to convert to a Unix path or to the path expected by the node libraries regardless of the path origin.

Example:

  1. // On Windows
  2. const fs = Plugin.fs;
  3. const path = Plugin.path;
  4. const filePath = path.join('/C/Program Files', 'Program/file.txt');
  5. console.log(filePath); // Prints '/C/Program Files/Program/file.txt'
  6. fs.writeFileSync(filePath, 'Hello.'); // Writes to 'C:\Program Files\Program\file.txt'
  7. console.log(Plugin.convertToOsPath(filePath)); // Prints 'C:\Program Files\Program\file.txt'

Isobuild Feature Packages

Starting with Meteor 1.2, packages can declare that they need a version of the Meteor tool whose Isobuild build system supports a certain feature. For example, packages must write api.use('isobuild:compiler-plugin@1.0.0') in order to call Plugin.registerCompiler. This means that a package can transition from the old registerSourceHandler API to registerCompiler and Version Solver will properly prevent the registerCompiler version from being chosen by older tools that don’t know how to handle it.

This is the known Isobuild feature “packages” sorted by the first release of Meteor which supports them.

Introduced in Meteor 1.2

  • compiler-plugin@1.0.0: Allows use of Plugin.registerCompiler.
  • linter-plugin@1.0.0: Allows use of Plugin.registerLinter.
  • minifier-plugin@1.0.0: Allows use of Plugin.registerMinifier.
  • isopack-2@1.0.0: This package is published only in isopack-2 format and won’t work in versionsof Meteor that don’t support that format.
  • prod-only@1.0.0: Allows use of the prodOnly flag in Package.describe.
  • isobuild:cordova@5.4.0: This package depends on a specific version of Cordova, most likely as a result of the Cordova plugins it depends on.