在package.json中找到未使用的npm包

有没有一种方法来确定你的package.json文件中是否有不再需要的包?

例如,当我尝试一个包,然后注释或删除代码,但忘记卸载它时,我最终得到了几个可以删除的包。

确定一个包是否可以安全删除的有效方法是什么?

257167 次浏览

如果你使用的是类似Unix的操作系统(Linux, OSX等),那么你可以使用findegrep的组合来搜索包含包名的require语句:

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

如果你搜索整个require('name-of-package')语句,记得使用正确类型的引号:

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

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

缺点是它不是全自动的,即它不能从package.json中提取包名并检查它们。您需要自己为每个包执行此操作。由于package.json只是JSON,因此可以编写一个小脚本,使用child_process.exec为每个依赖项运行此命令。让它成为一个模块。并将其添加到NPM回购…

你可以使用一个名为depcheck的npm模块(至少需要Node的10版本)。

  1. 安装模块:

     npm install depcheck -g
    
    
    or
    
    
    yarn global add depcheck
    
  2. 运行它并找到未使用的依赖项:

     depcheck
    

这种方法的好处是你不需要记住findgrep命令。

要运行不需要安装,使用npx:

npx depcheck

还有一个名为npm-check的包:

npm-check

检查过时的、不正确的和未使用的依赖项。

enter image description here

它是相当强大和积极发展的。它的功能之一是检查未使用的依赖项-对于这一部分,它使用了另一个答案中提到的depcheck模块。

fiskeben写道:

缺点是它不是全自动的,也就是说它不能从包中提取包名。Json并检查它们。您需要自己为每个包执行此操作。

如果由于某种原因depcheck不能正常工作,让我们自动执行Fiskeben的回答!(例如,我尝试用Typescript,它给出了不必要的解析错误)

为了解析package.json,我们可以使用软件jq。下面的shell脚本需要一个从哪里开始的目录名。

#!/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"

首先,它创建两个临时文件,我们可以在其中缓存包名和文件。

它以find命令开始。第一行和第二行使它忽略node_modulesbuild文件夹(或任何你想要的)。第三行包含允许的扩展名,你可以在这里添加更多,例如JSX或JSON文件。

函数将读取依赖类型。

首先,它__abc0 package.json。然后,jq获得所需的依赖项组。({} +的存在是为了在文件中没有对等依赖时不会抛出错误。)

之后,sed提取引号之间的部分,即包名。-n.../p告诉它从jq的JSON输出中输出匹配的部分,而不输出其他内容。然后我们将这个包名列表读入while循环。

RES是包名在引号中出现的次数。现在它是import/require'package' / "package"。大多数情况下都是这样。

然后我们简单地计算结果行数,然后打印结果。

警告:

  • 不会在不同的导入中找到文件,例如tsconfig.json文件(lib选项)
  • 只能对^USEDUNUSED文件手动grep
  • 对于大型项目来说很慢——shell脚本通常不能很好地扩展。但希望你不会跑这么多次。

我们可以使用下面的npm模块来实现这个目的:

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

这里的许多答案都是关于如何只找到未使用的物品。

我想…

自动——a) 找到 + b) 删除未使用的项目

选项2,下面似乎是较新的方式。


选项1:

  1. 安装该节点项目。
 $ npm install -g typescript tslint tslint-etc

  1. 在根目录下,添加一个新文件tslint-imports.json
{
"extends": [
"tslint-etc"
],
"rules": {
"no-unused-declaration": true
}
}

  1. 请自行承担运行风险,进行备份:)
$ tslint --config tslint-imports.json --fix --project .

选项2:Per @Alex &@JacopKane的建议,谢谢

// newer one line option
npx depcheck --json | jq '.dependencies[]' | xargs -L1 npm rm


// or
npm uninstall $(npx depcheck --oneline)
gombosg中的脚本比npm-check要好得多。
我做了一点修改,所以node_modules中的devdependencies也会被找到。
sass从未使用过,但在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"

与原始脚本的结果:

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

修改后:

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

如果你想选择站在哪个巨人的肩膀上

这里有一个链接来生成npm可用选项的简短列表;它过滤关键字unused packages

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

为什么我的答案只是一个链接?

通常我不会只提供一个链接。这个问题的答案应该不那么费时。解决方案依赖于最新的软件。推荐一个可能已经停止维护的特定软件(这里的一些建议的情况)是没有什么用处的。帮助人们找到一些当前的东西似乎是合适的。

检查未使用的依赖关系

npm install depcheck -g
depcheck

enter image description here

检查过时的图书馆

npm outdated

enter image description here

在Yarn 2。X及以上,使用:

yarn dlx depcheck

Yarn DLX被设计用来执行一次性脚本,这些脚本可能已经在Yarn 1.x中作为全局包安装。管理系统级包超出了yarn的范围。为了反映这一点,yarn全局已被删除。

来源:https://yarnpkg.com/getting-started/migration#use-yarn-dlx-instead-of-yarn-global

除非我误解了gombosg脚本的某些内容。这里是脚本扩展的一个更快版本,默认为'find',但可以很容易地修改为使用'fd'来查找功能。

不同之处在于,它首先查找所有相关文件,然后从所有相关文件中一次性找到grep包,而不是一个文件一个文件地查找。

可控制并发性,默认为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"


用于检查未使用的依赖项,库和未导入的文件

 npx unimported

我已经创建了一个包unused-package (https://www.npmjs.com/package/unused-package),它返回任何未使用的包,或者如果包是devDependency,但作为正常依赖项安装

创建一个文件并将此代码添加到您的文件中

const check = require("unused-package");


check({ entries: ['entry path to your code'] }).then((res) => {
console.log(res) // list of packages returned by library
});


used-package相对于depcheck包的一个优点是unused-package支持多个入口路径。