ChatGPT解决这个技术问题 Extra ChatGPT

Find unused npm packages in package.json

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?


M
Mostafiz Rahman

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

Install the module: npm install depcheck -g or yarn global add depcheck 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 

depcheck-es6 is now merged into depcheck
doesnt look useful. I am using the standard angular2 cli setup and depcheck lists every package as unused which is just wrong
NB. depcheck doesn't take into account packages used in scripts specified in package.json
To run it just once (w/o installation) - use npx: npx depcheck
Didn't work for me. It listed all the packages as unused.
a
alecxe

There is also a package called npm-check:

npm-check Check for outdated, incorrect, and unused dependencies.

https://i.stack.imgur.com/ldoRq.png

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.


Seems to give me the same results as depcheck. It looks like it even uses depcheck to find the unused dependencies.
npm outdatedchecks and lists current, wanted and latest package versions. No list of unused packages though.
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
Seems a bit outdated now. It includes high severity vulnerabilities right now...
S
Sathiamoorthy

Check the unused dependencies

npm install depcheck -g
depcheck

https://i.stack.imgur.com/UkiHg.png

Check the outdated library

npm outdated

https://i.stack.imgur.com/wy7rS.png


m
mMo

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

Adding -P 32 switch to your xargs will result in a huge speedup.
Best solution compared to depcheck and derivatives. Adding --max-procs|-P 32 greatly improves the speed.
Great script that nicely extended the orginal one, but it got unusable slow (even xargs -P options) on a large react app. Re-organized file searches and shared a version that should produce same output, but not necessary in the same order.
T
Transformer

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:

Install this node project.

 $ npm install -g typescript tslint tslint-etc

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

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

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

But this is going to remove from the js files only. But ya still good.
how about npx depcheck --json | jq '.dependencies[]' | xargs -L1 npm rm
tslint is deprecated as of 2019
g
gombosg

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.


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?
f
fiskeben

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


What about .jsx files and .ts files etc :D
Apparently using this approach we are not using react module in our React app :D
S
Sapnesh Naik

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: https://yarnpkg.com/getting-started/migration#use-yarn-dlx-instead-of-yarn-global


u
user11403389

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 ;-)
K
Kay V

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

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.


M
Manwe

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
# https://github.com/sharkdp/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"


M
Mujahidul Islam

For checking unused dependencies, libraries and unimported files

 npx unimported 

Unable to locate entry points for this node project. Please declare them in package.json or .unimportedrc.json