Using npm Packages
This guide covers how to find, install, and use npm packages in your Meteor application.
Searching for packages
You can find npm packages using:
- npmjs.com - The official npm registry
- npms.io - Searches by package quality, maintenance status, and popularity
npm on the client
Meteor uses bundling technology similar to webpack to provide a Node-like environment on the client, allowing many npm packages intended for the server to run in the browser.
When creating a new application, Meteor installs the meteor-node-stubs npm package to provide browser-friendly implementations of Node's built-in modules like path, buffer, util, etc.
INFO
Meteor's module system avoids bundling any stub modules if they are not used, so there is no cost to keeping meteor-node-stubs in your dependencies.
Installing npm packages
npm packages are configured in a package.json file at the root of your project. If you create a new Meteor project, you will have such a file created for you. If not, you can run meteor npm init to create one.
To install a package into your app:
meteor npm install --save momentThis will:
- Update your
package.jsonwith information about the dependency - Download the package into your app's local
node_modulesdirectory
Typically, you don't check the node_modules directory into source control. Your teammates run meteor npm install to get up to date when dependencies change:
meteor npm installDevelopment dependencies
If the package is just a development dependency (used for testing, linting, etc.), use --save-dev:
meteor npm install --save-dev eslintThis way, production builds can run npm install --production and avoid installing packages they don't need.
TIP
Meteor comes with npm bundled so that you can type meteor npm without worrying about installing it yourself. You can also use a globally installed npm if you prefer.
Using npm packages
To use an npm package from a file in your application, use import:
import moment from 'moment';
// This is equivalent to the standard Node.js require:
const moment = require('moment');This imports the default export from the package into the symbol moment.
You can also import specific functions using destructuring:
import { isArray } from 'lodash';You can also import other files or entry points from a package:
import { parse } from 'graphql/language';Importing styles from npm
Using any of Meteor's supported CSS pre-processors, you can import style files from npm packages.
Importing with an absolute path using the {} syntax (with Less):
@import '{}/node_modules/npm-package-name/button.less';Importing with a relative path:
@import '../../node_modules/npm-package-name/colors.less';You can also import CSS directly from a JavaScript file:
import 'npm-package-name/stylesheets/styles.css';WARNING
When importing CSS from a JavaScript file, that CSS is not bundled with the rest of the CSS processed with the Meteor build tool. Instead, it is put in your app's <head> tag inside <style>...</style> after the main concatenated CSS file.
Building with other assets from npm
Meteor supports building other assets (like fonts) that are located in your node_modules directory by symbolic linking to those assets from either the /public or /private directories:
cd public
ln -s ../node_modules/font-awesome/fonts ./fontsAny assets made available via symlinks in /public and /private will be copied into the Meteor application bundles when using meteor build.
Recompiling npm packages
Meteor does not recompile packages installed in your node_modules by default. However, you can configure recompilation of specific npm packages through the meteor.nodeModules.recompile configuration object in your package.json file:
{
"name": "your-application",
"meteor": {
"nodeModules": {
"recompile": {
"very-modern-package": ["client", "server"],
"alternate-notation": true,
"somewhat-modern-package": "legacy",
"another-package": ["legacy", "server"]
}
}
}
}The keys are npm package names, and the values specify for which bundles those packages should be recompiled.
For example, if an npm package uses modern JavaScript syntax that's fine for modern browsers and server code, but needs to be recompiled for the legacy bundle, specify "legacy" or ["legacy"] as the value.
Using async npm packages
Many npm packages use asynchronous, callback or promise-based APIs. In Meteor 3, you should use async/await patterns:
import { getData } from 'some-async-package';
// In a Method
Meteor.methods({
async 'myMethod'() {
const result = await getData();
return result;
}
});
// In a publication (for setup, not the return)
Meteor.publish('myPublication', async function() {
const config = await getConfigAsync();
return MyCollection.find({ type: config.type });
});Wrapping callback-based APIs
If you have an npm package that uses callbacks, you can wrap it with Promise:
import { legacyAsyncFunction } from 'some-package';
function promisifiedFunction(args) {
return new Promise((resolve, reject) => {
legacyAsyncFunction(args, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
}
// Now you can use async/await
const result = await promisifiedFunction(myArgs);Many Node.js core modules also provide promise-based versions via util.promisify:
import { promisify } from 'util';
import { readFile } from 'fs';
const readFileAsync = promisify(readFile);
const contents = await readFileAsync('/path/to/file', 'utf8');Package lock files
package.json typically encodes a version range, so each npm install command can sometimes lead to different results if new versions have been published.
To ensure your entire team uses the exact same version of each package, use package-lock.json:
# The lock file is automatically created/updated when you install
meteor npm install --save moment
# Commit package-lock.json to source control
git add package-lock.json
git commit -m "Update dependencies"When other team members pull changes, they run:
meteor npm installThis will use the versions specified in package-lock.json.
Peer dependencies
Some npm packages declare peer dependencies, which means they expect certain packages to be installed by your application. If you see peer dependency warnings, you may need to install those packages:
meteor npm install --save react react-domCommon issues
Binary dependencies
Some npm packages include native binary components. These packages need to be rebuilt when:
- You switch Node.js versions
- You deploy to a different architecture
If you encounter issues, try:
meteor npm rebuildModule resolution
If you're having trouble importing a package, check:
- The package is installed in
node_modules - You're using the correct import path
- The package's
mainfield in itspackage.jsonpoints to the right file
Version conflicts
If you have conflicting versions of the same package, npm will try to resolve them. You can check for issues with:
meteor npm lsTo see which packages depend on a specific package:
meteor npm ls package-name
