Velvet Star Monitor

Standout celebrity highlights with iconic style.

news

Find unused npm packages in package.json

Writer Emily Wong

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?

0

12 Answers

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 
20

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.

4

Check the unused dependencies

npm install depcheck -g
depcheck

enter image description here

Check the outdated library

npm outdated

enter image description here

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
#
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
3

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

what if.. I wanted to..

AUTOmatically -- a) find + b) Remove the unused items


Option 1:

  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 .

Option 2: Per @Alex

npx depcheck --json | jq '.dependencies[]' | xargs -L1 npm rm
3

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.
1

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...

2

We can use the below npm module for this purpose:

1

In Yarn 2.x and above, use:

yarn dlx depcheck

yarn dlx is designed to execute one off scripts that may have been installed as global packages with yarn 1.x. Managing system-wide packages is outside of the scope of yarn. To reflect this, yarn global has been removed.

Source:

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

Why is my answer just a link?

Typically I wouldn't provide just a link. This question deserves a less time-sensitive answer. The solution relies on up-to-date software. Recommending a specific piece of software that may have stopped being maintained (the case with some of the recommendations here) is of little use. Helping people find something current seems appropriate.

0

Unless I've misunderstood something about the scripts by gombosg and nMo. Here's a faster version of nMo script-extensions with defaulting to 'find', but can be easily modified to use 'fd' for find functionality.

Changes are that it first finds all relevant files and then grep packages from all relevant files on one go and not a file-by-file bases.

Concurrency can be controlled and defaults to 8.

#!/bin/bash
DIRNAME=${1:-.}
cd "$DIRNAME"
FILES=$(mktemp)
PACKAGES=$(mktemp)
export NUMCONCURRENT=8
function findCmd { startPath=${1:-.} find "$startPath" \ -path ./node_modules -prune -or \ -path ./build -prune -or \ \( -name "*.ts" -or -name "*.js" -or -name "*.json" \) -print
}
# use fd
#
function findCmd_fd { startPath=${1:-.} fd -t f '(js|ts|json)$' "$startPath"
}
function check { cat package.json \ | jq "{} + .$1 | keys" \ | sed -n 's/.*"\(.*\)".*/\1/p' > "$PACKAGES" echo "--------------------------" echo "Checking $1..." findCmd > "$FILES" while read PACKAGE do #echo "node_modules/${PACKAGE}" if [ -d "node_modules/${PACKAGE}" ]; then findCmd node_modules/${PACKAGE} >> $FILES fi done < $PACKAGES export FILES export SQ="'" xargs -P ${NUMCONCURRENT:-1} -r -a "$PACKAGES" -I[] bash -c ' PACKAGE="[]" RES=$(cat "$FILES" | xargs -r egrep -i "(import|require|loader|plugins|${PACKAGE}).*[\"${SQ}](${PACKAGE}|.?\d+)[\"${SQ}]" | wc -l) if [ $RES = 0 ] then echo -e "UNUSED\t\t $PACKAGE" else echo -e "USED ($RES)\t $PACKAGE" fi ' [ -f "$PACKAGES" ] && rm "$PACKAGES" [ -f "$FILES" ] && rm "$FILES"
}
check "dependencies"
check "devDependencies"
check "peerDependencies"

For checking unused dependencies, libraries and unimported files

 npx unimported 
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy