depcheck – Linting dependency usage

In my previous post, I wrote about choosing dependencies wisely. The NPM ecosystem is known for its small packages with a lot of dependencies. You can quickly lose track about your dependency usage. Do you have all dependencies configured correctly? Are all of your dependencies still in use? I want to present you

depcheck
, a small utility to keep track of your dependency usage.

When working with dependencies from NPM, you can lose track about two cases: Either you still have a dependency declared in your

package.json
that you aren’t using anymore, or never used. Or you are using a package that you don’t depend on.

The first case can happen quickly: You replaced and existing implementation with a new one that doesn’t require the dependency anymore. Or you simply remove the feature that the used package. Or you just lost track about which dependency you actually use while implementing a new feature. At first, an unused dependency causes no harm. But they can become a maintenance problem. More dependencies increase the complexity of your application. Even an unused dependency can contain security vulnerabilities that might cost time fixing. This is even a problem with automated dependency upgrades via Dependabot, but could be avoided if the dependency didn’t exist at all. Each dependency increases the install time of your project. This might be negligible on your local device, but due to many builds it can quickly sum up in your CI environment.

Missing dependencies can be a risk too. A missing dependency can happen if you are importing a package that another package brings as an indirect dependency. This can happen quickly via code completion in your IDE — If it’s suggested, then it’s available, right? While the code runs fine, this can turn out as a problem later. What if the package that brings the dependency is updated? It could update the package that you depend on to a newer version that contains a breaking change. Or it could stop bringing the dependency at all. Or you could stop using the package that brings the dependency. In these cases, your code breaks and it might not be that obvious why it broke.

A solution to this problem is

depcheck
. A small CLI utility that can help you with keeping track of your dependencies.

Depcheck is a tool for analyzing the dependencies in a project to see: how each dependency is used, which dependencies are useless, and which dependencies are missing from 

package.json
.

depcheck repository on GitHub

depcheck
is easy to setup — you might not even need to install it. Simply run it from your package’s root folder via
npx
:

% npx depcheck

Unused dependencies
* redux
* stylis
Unused devDependencies
* @types/jest
* canvas
* prettier-plugin-organize-imports
Missing dependencies
* readline: ./src/data/Feed.ts

The output is simple and self-explaining.

depcheck
is analyzing your code and detects every package you import. It has support for JavaScript, TypeScript, and some other languages. You might wonder what happens if you have dependency that you aren’t using in your code directly. One example are
eslint
plugins.
depcheck
has built-in support for some popular tools and detects their plugins, like
eslint
,
prettier
, or
webpack
so that you don’t have to worry about false positives for them.

However, there are some edge cases where

depcheck
isn’t able to recognize whether a dependency is in use or not. For example, the typings for
jest
, which are automatically configure in your
tsconfig
are not detected as such. Another example is the
canvas
package, which is a peer dependency of
jsdom
and only imported if it’s installed. But these corner cases, or false positives, are something you can configure for your project.
depcheck
has a CLI argument that you can use to configure a list of dependencies to ignore. Besides that, there are some more configuration options available. Next, I want to show how I prefer to use
depcheck
.

My Setup

My

depcheck
setup includes three features:

  • A local NPM script that you can run manually,
  • a
    husky
    /
    lint-staged
    check,
  • and a CI step.

Let’s have a look at the NPM script first. I like to install

depcheck
as a
devDependency
, so that I don’t have to install it every time I want to run it. Adding a script is also useful to configure common CLI arguments that you want to pass every time, like an ignore list for false positives. Sometimes it’s also necessary to exclude output folders from the check. Output folders can lead to false positives, for example if they contain stale builds that reference packages that aren’t available in your
package.json
anymore. If you prefer running it via
npx
,
depcheck
also supports a configuration file format.

  "devDependencies": {
    "depcheck": "^1.4.2",
  }
  "scripts": {
    "depcheck": "depcheck --ignores=@types/jest,netlify-cli,prettier-plugin-organize-imports,…",
  },

I always prefer to fail early. In the best case you get feedback before you create a PR and the CI pipeline fails. This can be accomplished using

pre-commit
-hooks. Nice tools for that are
husky
and
lint-staged
.
husky
takes care that your
pre-commit
-hook is registered in your local Git working copy when installing NPM packages.
lint-staged
takes care to run the right check, depending on the changed files.
husky
can be setup with some simple steps, afterwards you can call
lint-staged
from your
pre-commit
-hook. For this setup I run
depcheck
every time the
package.json
or another source file is changed. You need to run it in
bash
, as
lint-staged
would otherwise pass all changed filenames to
depcheck
, but it doesn’t need them. This is the
lint-staged
configuration I add to my
package.json
:

  "lint-staged": {
    "{package.json,js,jsx,ts,tsx}": [
      "bash -c \"yarn depcheck\""
    ]
  }

Integrating

depcheck
with your CI is easy. In my case I’m using GitHub Actions. If you already have the NPM script, you can simply execute it. That way you can catch PRs that accidentally introduce unused dependencies or forgot to remove old ones quickly.

- name: depcheck
  run: yarn depcheck

With

depcheck
, you won’t pollute you project with unused dependencies anymore. And it also saves you from missing dependencies. Now that you have your dependencies under control, start building something cool!