Meteor Debugging Strategies

This page presents guidance on how to debug your Meteor application.

Use ESLint to detect errors early

A simple first step in debugging your Meteor application is to invoke meteor npm run lint and ensure that there are no ESLint errors in your code base. This is always a good first step because ESLint doesn’t just check for formatting problems, it also finds a variety of semantic errors in your code. Here are two examples:

1. Detecting unexported objects.

For example, consider this invocation and its output:

$ meteor npm run lint

> meteor-application-template-react@ lint /Users/philipjohnson/github/philipmjohnson/digits/app
> eslint --quiet --ext .jsx --ext .js ./imports

  5:7  error  'Landing' is defined but never used  no-unused-vars

✖ 1 problem (1 error, 0 warnings)

npm ERR! errno 1
npm ERR! meteor-application-template-react@ lint: `eslint --quiet --ext .jsx --ext .js ./imports`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the meteor-application-template-react@ lint script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/philipjohnson/.npm/_logs/2019-11-02T01_48_49_218Z-debug.log
~/g/p/d/app (master|✚1) $

If you then open Landing.jsx in IntelliJ, you see the same error in context:

Hopefully, at this point, the problem is pretty obvious: the Landing React component was not exported from this file.

2. Detecting mispelled variables.

Another really common source of subtle Javascript problems come from mispellings of variable names. Unlike Java, Javascript allows implicit variable declaration, which means that if you mispell a variable name, you’re simply declaring a new variable. Our ESLint configuration flags implicit variable declarations as an error, which means that mispellings are detected for you.

One last comment: to make this tip work, you need to “keep the code clean”. If running ESLint produces hundreds of warnings, then you’re not going to see the important ones.

Use default export and named exports correctly

The templates used in this class use both “default” exports and “named” exports. For example, files containing the implementation of React components generally use “default” export, since only a single object (the React component) is made available outside the file. On the other hand, API files that define collections often export multiple objects (the collection, the associated schema, etc.) and so they use “named” exports in order to allow users to import the object of interest.

Unfortunately, the syntax is very slightly different for importing objects depending upon whether they were exported in a “named” or “default” format.

For example, if a component is exported using the default export mechanism, such as:

export default class Landing extends React.Component { ...

then the import statement should look like this:

import Landing from '../pages/Landing';

On the other hand, if objects are exported using the named export mechanism, such as:

export { Contacts, ContactsSchema };

then the import statement should look like this:

import { Contacts } from '../../api/contact/Contacts';

The only syntactic difference is the presence of curly braces for named imports, and the absence of them for default exports, but if you get this wrong (and it’s easy), then the system will fail in strange ways.

This debugging situation is confusing enough that I made a short screencast called Meteor Debugging: Named vs. Default Exports. Please check it out to see live examples of the kinds of errors you can get and how to track this problem down.

Use sample data as “test” data

The sooner you detect that you’ve introduced an error into your code base, the easier it is to fix (because you know it was a recent change that broke things).

One way to detect errors “sooner” is to have a high quality sample data set that initializes the database when it is empty. This can quickly detect all sorts of potential inconsistencies in your schemas, publications, and user interface components.

So, each time you make a change to, or extend your system’s data model in some way, make sure that your sample data in settings.development.json (and settings.production.json) is updated to “exercise” the change or extension. This will not guarantee that all bugs have been removed, but will often help you discover and fix many of them.

Don’t forget that you must clear the database of its current contents in order to load the changed sample data and actually test for problems. For details on how to do that, see Refreshing data in development and deployment.

Verify data flow

A common scenario is that a page does not display the data that you expect it to display. This is often due to a problem with your publications, subscriptions, or MiniMongo query statement. There are a number of things you need to check:

  1. Verify that the server-side MongoDB database contains the correct data.
  2. Verify that the client-side MiniMongo database contains the correct data for the page that requires it.
  3. If the answer to (1) and (2) is yes, then verify that the MiniMongo query is returning the correct data.

Another common scenario is that “the data displays fine on my laptop, but not in the deployed application”. Fortunately, the same set of questions will help you determine what is different between the two environments.

There are two screencasts which go into detail on how to verify data flow: Understanding data in Meteor in development mode and Understanding data in Meteor in deployment mode.

Spell your subscription names correctly

For simplicity, the sample applications all use a string to name each publication which is not exported from the file. This means your subscriptions must be sure to spell the publication string name exactly correctly.

If you misspell the name of the publication in your subscription call, then the associated page with show the “Loading data” icon forever.

Ask a smart question

If all else fails, ask a smart question. My rule of thumb is to not spend more than 30 minutes trying to debug your problem without asking for assistance.