317

Is there a way to determine if you have packages in your package.json file that are no longer needed?

For instance, when trying out a package and later commenting or deleting code, but forgetting to uninstall it, I end up with a couple packages that could be deleted.

What would be an efficient way to determine if a package could safely be deleted?

danwellman
  • 8,179
  • 6
  • 49
  • 75
Josh C
  • 4,471
  • 2
  • 22
  • 21

9 Answers9

396

You can use an npm module called depcheck (requires at least version 10 of Node).

  1. Install the module:

     npm install depcheck -g
    
     or
    
     yarn global add depcheck
    
  2. Run it and find the unused dependencies:

     depcheck
    

The good thing about this approach is that you don't have to remember the find or grep command.

To run without installing use npx:

npx depcheck 
Mostafiz Rahman
  • 6,939
  • 6
  • 45
  • 68
German Attanasio
  • 17,275
  • 7
  • 44
  • 61
  • 1
    `return new Promise(function (resolve, reject) {: ReferenceError: Promise is not defined` ... too bad. gonna go with npm-check – Boern Dec 16 '15 at 22:27
  • 11
    depcheck-es6 is now merged into depcheck – cyberwombat Jan 04 '16 at 00:27
  • 71
    doesnt look useful. I am using the standard angular2 cli setup and `depcheck` lists every package as `unused` which is just wrong – phil294 Feb 10 '17 at 19:07
  • I used this over npm-check because there's a module for gulp integration: https://github.com/depcheck/gulp-depcheck. – Westy92 Mar 20 '17 at 21:08
  • This package completely lagged down my Mac running High Sierra, I would not recommend using it. – lapint May 04 '18 at 15:22
  • 2
    It shows some dependencies as unused which are actually getting used such as babel-cli, css-loader, sass-loader and many more which are getting used in build process. – Sakshi Nagpal May 17 '18 at 06:54
  • For typescript, install using `npm install -g depcheck typescript`. However, even with this option, every dependency was listed as unused. – Doug Domeny Jun 20 '18 at 14:05
  • 6
    NB. depcheck doesn't take into account packages used in scripts specified in package.json – Javier Arias Oct 02 '18 at 15:02
  • 26
    To run it just once (w/o installation) - use [npx](https://www.npmjs.com/package/npx): `npx depcheck` – Kiril Nov 07 '18 at 17:59
  • 2
    I had a grunt build, and this suggested to remove all grunt packages under devDependencies. Not a good idea :) – swateek Dec 17 '18 at 13:06
  • There is an option to ignore certain packages like `eslint-*` or `gulp-`. – German Attanasio Dec 17 '18 at 14:17
  • so now who will remove this `depcheck`? – sanjeev Feb 26 '19 at 12:24
  • 3
    Doesn't work. I just ran `depcheck` on my Gatsby project and it listed almost all of my packages as `unused` even though most of them are actually used. – Atte Juvonen Mar 14 '19 at 00:03
  • @AtteJuvonen there is a way to specify which pages should be skipped like `eslint` or `babel`. What are the packages that are being listed for you? – German Attanasio Mar 15 '19 at 11:26
  • It lists a lot of packages that are actually used, including `gatsby-plugin-google-analytics` and `typescript`. – Atte Juvonen Mar 15 '19 at 21:14
  • 8
    Didn't work for me. It listed all the packages as unused. – dev27 May 20 '19 at 22:20
  • Running on old angular project saying `No depcheck issue` which is wrong as there is definitely some unused packages I can tell – angularrocks.com Feb 03 '20 at 06:44
153

There is also a package called npm-check:

npm-check

Check for outdated, incorrect, and unused dependencies.

enter image description here

It is quite powerful and actively developed. One of it's features it checking for unused dependencies - for this part it uses the depcheck module mentioned in the other answer.

alecxe
  • 414,977
  • 106
  • 935
  • 1,083
  • 13
    Seems to give me the same results as depcheck. It looks like it even uses depcheck to find the unused dependencies. – Alex K Sep 14 '18 at 16:55
  • 5
    ```npm outdated```checks and lists current, wanted and latest package versions. No list of unused packages though. – mgarde Oct 25 '18 at 11:34
  • 5
    doesnt look useful as well. I am using the standard angular setup and this also lists every package as unused which is just as wrong – Kyle Burkett Jun 27 '19 at 17:00
6

If you're using a Unix like OS (Linux, OSX, etc) then you can use a combination of find and egrep to search for require statements containing your package name:

find . -path ./node_modules -prune -o -name "*.js" -exec egrep -ni 'name-of-package' {} \;

If you search for the entire require('name-of-package') statement, remember to use the correct type of quotation marks:

find . -path ./node_modules -prune -o -name "*.js" -exec egrep -ni 'require("name-of-package")' {} \;

or

find . -path ./node_modules -prune -o -name "*.js" -exec egrep -ni "require('name-of-package')" {} \;

The downside is that it's not fully automatic, i.e. it doesn't extract package names from package.json and check them. You need to do this for each package yourself. Since package.json is just JSON this could be remedied by writing a small script that uses child_process.exec to run this command for each dependency. And make it a module. And add it to the NPM repo...

fiskeben
  • 3,146
  • 3
  • 26
  • 32
5

fiskeben wrote:

The downside is that it's not fully automatic, i.e. it doesn't extract package names from package.json and check them. You need to do this for each package yourself.

Let's make Fiskeben's answer automated if for whatever reason depcheck is not working properly! (E.g. I tried it with Typescript and it gave unnecessary parsing errors)

For parsing package.json we can use the software jq. The below shell script requires a directory name where to start.

#!/bin/bash
DIRNAME=${1:-.}
cd $DIRNAME

FILES=$(mktemp)
PACKAGES=$(mktemp)

find . \
    -path ./node_modules -prune -or \
    -path ./build -prune -or \
    \( -name "*.ts" -or -name "*.js" -or -name "*.json" \) -print > $FILES

function check {
    cat package.json \
        | jq "{} + .$1 | keys" \
        | sed -n 's/.*"\(.*\)".*/\1/p' > $PACKAGES

    echo "--------------------------"
    echo "Checking $1..."
    while read PACKAGE
    do
        RES=$(cat $FILES | xargs -I {} egrep -i "(import|require).*['\"]$PACKAGE[\"']" '{}' | wc -l)
        if [ $RES = 0 ]
        then
            echo -e "UNUSED\t\t $PACKAGE"
        else
            echo -e "USED ($RES)\t $PACKAGE"
        fi
    done < $PACKAGES
}

check "dependencies"
check "devDependencies"
check "peerDependencies"

First it creates two temporary files where we can cache package names and files.

It starts with the find command. The first and second line make it ignore the node_modules and build folders (or whatever you want). The third line contains allowed extensions, you can add more here e.g. JSX or JSON files.

A function will read dependendy types.

First it cats the package.json. Then, jq gets the required dependency group. ({} + is there so that it won't throw an error if e.g. there are no peer dependencies in the file.)

After that, sed extracts the parts between the quotes, the package name. -n and .../p tells it to print the matching parts and nothing else from jq's JSON output. Then we read this list of package names into a while loop.

RES is the number of occurrences of the package name in quotes. Right now it's import/require ... 'package'/"package". It does the job for most cases.

Then we simply count the number of result lines then print the result.

Caveats:

  • Won't find files in different imports e.g. tsconfig.json files (lib option)
  • You have to grep manually for only ^USED and UNUSED files.
  • It's slow for large projects - shell scripts often don't scale well. But hopefully you won't be running this many times.
gombosg
  • 594
  • 7
  • 7
  • 1
    Editors sometimes cause imports to wrap into multiple lines. Would this script catch statements where ‘import’ or ‘require’ would be on a different line than the ‘from “PACKAGE_NAME”’? In other words, does it ignore whitespace in import or require statements? – vdiaz1130 Mar 11 '20 at 13:31
3

The script from gombosg is much better then npm-check.
I have modified a little bit, so devdependencies in node_modules will also be found.
example sass never used, but needed in sass-loader

#!/bin/bash
DIRNAME=${1:-.}
cd $DIRNAME

FILES=$(mktemp)
PACKAGES=$(mktemp)

# use fd
# https://github.com/sharkdp/fd

function check {
    cat package.json \
        | jq "{} + .$1 | keys" \
        | sed -n 's/.*"\(.*\)".*/\1/p' > $PACKAGES
    echo "--------------------------"
    echo "Checking $1..."
    fd '(js|ts|json)$' -t f > $FILES
    while read PACKAGE
    do
        if [ -d "node_modules/${PACKAGE}" ]; then
            fd  -t f '(js|ts|json)$' node_modules/${PACKAGE} >> $FILES
        fi
        RES=$(cat $FILES | xargs -I {} egrep -i "(import|require|loader|plugins|${PACKAGE}).*['\"](${PACKAGE}|.?\d+)[\"']" '{}' | wc -l)

        if [ $RES = 0 ]
        then
            echo -e "UNUSED\t\t $PACKAGE"
        else
            echo -e "USED ($RES)\t $PACKAGE"
        fi
    done < $PACKAGES
}

check "dependencies"
check "devDependencies"
check "peerDependencies"

Result with original script:

--------------------------
Checking dependencies...
UNUSED           jquery
--------------------------
Checking devDependencies...
UNUSED           @types/jquery
UNUSED           @types/jqueryui
USED (1)         autoprefixer
USED (1)         awesome-typescript-loader
USED (1)         cache-loader
USED (1)         css-loader
USED (1)         d3
USED (1)         mini-css-extract-plugin
USED (1)         postcss-loader
UNUSED           sass
USED (1)         sass-loader
USED (1)         terser-webpack-plugin
UNUSED           typescript
UNUSED           webpack
UNUSED           webpack-cli
USED (1)         webpack-fix-style-only-entries

and the modified:

Checking dependencies...
USED (5)         jquery
--------------------------
Checking devDependencies...
UNUSED           @types/jquery
UNUSED           @types/jqueryui
USED (1)         autoprefixer
USED (1)         awesome-typescript-loader
USED (1)         cache-loader
USED (1)         css-loader
USED (2)         d3
USED (1)         mini-css-extract-plugin
USED (1)         postcss-loader
USED (3)         sass
USED (1)         sass-loader
USED (1)         terser-webpack-plugin
USED (16)        typescript
USED (16)        webpack
USED (2)         webpack-cli
USED (2)         webpack-fix-style-only-entries
mMo
  • 105
  • 6
2

Check the unused dependencies.

npx depcheck

(OR)

npm install depcheck -g
depcheck

enter image description here

Check the outdated library.

npm outdated

enter image description here

Sathia
  • 2,184
  • 2
  • 20
  • 37
1

We can use the below npm module for this purpose:

https://www.npmjs.com/package/npm-check-unused

  • it revealed some not used ones but also used ones, still helpful I guess :-) It doesn't understand webpack loaders ;-) – OZZIE Sep 02 '19 at 13:07
1

many of the answer here are how to find unused items.

I wanted to remove them automatically.

  1. Install this node project.

    $ npm install -g typescript tslint tslint-etc


  1. At the root dir, add a new file tslint-imports.json

    { "extends": [ "tslint-etc" ], "rules": { "no-unused-declaration": true } }


  1. Run this at your own risk, make a backup :)

    $ tslint --config tslint-imports.json --fix --project .

Transformer
  • 3,100
  • 17
  • 40
0

if you want to choose upon which giant's shoulders you will stand

here is a link to generate a short list of options available to npm; it filters on the keywords unused packages

https://www.npmjs.com/search?q=unused%20packages

Kay V
  • 1,917
  • 12
  • 14