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?
This question is related to
node.js
dependencies
npm
many of the answer here are how to find unused items.
I wanted to remove them automatically.
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 .
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 cat
s 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:
tsconfig.json
files (lib
option)grep
manually for only ^USED
and UNUSED
files.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...
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
here is a link to generate a short list of options available to npm; it filters on the keywords unused packages
We can use the below npm module for this purpose:
Source: Stackoverflow.com