Home

Awesome

ember-cli-dependency-lint Build Status

This addon adds lint tests that verify only one version of any given addon will be activated in the final built application.

Motivation

Suppose you're happily building an application using ember-modal-dialog, which in turn relies on ember-wormhole at 0.3.x. You then go add ember-power-select, which relies also relies on ember-wormhole via ember-basic-dropdown, but at 0.5.x. Your dependencies might now look like this:

my-app
├─┬ ember-modal-dialog
│ └── ember-wormhole@0.3.6
└─┬ ember-power-select
  └─┬ ember-basic-dropdown
    └── ember-wormhole@0.5.1

Your package manager notices the conflicting version requirements for ember-wormhole and helpfully makes sure each addon gets the version it's asking for. But your final built application will only have one copy of ember-wormhole—which version will it be?

In the end, Ember CLI will merge both versions together, with files from one version clobbering files from the other whenever they have the same name. This also means either ember-modal-dialog or ember-power-select will wind up attempting to use a version of ember-wormhole that it's not expecting, which can lead to anything from hard exceptions to subtle behavioral bugs.

Solution

In the scenario described above, the version conflict arose because of adding a new dependency, but it can also happen when you update an existing one. Regardless of how it happens, it may or may not immediately be obvious that something is wrong. The things that break may be subtle, or in untested edges cases in your application.

The purpose of this addon is to detect that situation as soon as it happens and inform you about it, allowing you the opportunity to make an informed decision about how to handle it.

Usage

For each addon in your project, ember-cli-dependency-lint will create a passing or failing test case depending on whether you have conflicting versions of that addon present. This way, the next time you run your tests after introducing a dependency conflict, you'll immediately know about the problem.

image

You can also manually run ember dependency-lint to get a more detailed report. This can be useful while debugging a dependency conflict, as it's much faster than rebuilding your test suite each time.

image

Run ember help dependency-lint for more details on this command.

Dealing with Conflicts

In the ember-wormhole example above, you have several options you might choose from:

Build-time Addons

Some addons don't actually add files to your application tree, so they don't have the conflict problem described above. In fact, for some addons (like preprocessors such as ember-cli-babel), insisting on a single version is undesirable. Different addons your app uses should be able to compile using whatever tooling they like without conflicting with one another.

Out of the box, this addon automatically allows for multiple arbitrary versions of:

Instructions for allowing multiple versions of other addons (or overriding these defaults) can be found below.

Configuration

Configuration for this addon is specified in a dedicated file in your project's config folder. For apps, this will be config/dependency-lint.js, and for addons, this will be the dummy app's tests/dummy/config/dependency-lint.js.

Lint Tests

For each addon dependency in your project, ember-cli-dependency-lint will generate a passing or failing test case (similar to other linting addons like ember-cli-eslint). If you only ever want to manually check your dependencies, you can set the generateTests flag to false.

// config/dependency-lint.js
module.exports = {
  generateTests: false
};

Allowed Versions

Out of the box, ember-cli-dependency-lint expects to find at most one version of any addon in an app's dependency tree, but it doesn't care precisely what that version is. To either tighten or loosen that restriction for a given addon, you can provide a semver specifier. For build-time-only addons, adding an entry here can be useful, but if the conflicting addon has runtime code, using resolutions or one of the other approaches outlined in Dealing with Conflicts above is strongly recommended.

// config/dependency-lint.js
module.exports = {
  allowedVersions: {
    // Fails unless every instance of addon-a is exactly version 1.2.3
    'addon-a': '1.2.3',

    // Fails unless every instance of addon-b is either 1.2.3 or 1.2.4
    'addon-b': '1.2.3 || 1.2.4',

    // Allows any version of addon-c such that 1.0.4 <= version < 2.0.0
    'addon-c': '^1.0.4',

    // Allows any number of arbitrary versions of addon-d (default for the addons listed above in Build-time Addons)
    'addon-d': '*'
  }
};