npm extraneous error 经历

今天在例行检查清理 npm package 时遇到了狗血的npm ERR! extraneous问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ npm ls -gp --depth=0
/usr/local/lib
/usr/local/lib/node_modules/babel-eslint
/usr/local/lib/node_modules/bower
/usr/local/lib/node_modules/browserify
/usr/local/lib/node_modules/coffee-script
/usr/local/lib/node_modules/doctoc
/usr/local/lib/node_modules/electron-prebuilt
/usr/local/lib/node_modules/eslint
/usr/local/lib/node_modules/eslint-plugin-react
/usr/local/lib/node_modules/gitbook-cli
/usr/local/lib/node_modules/google-protobuf
/usr/local/lib/node_modules/graceful-fs
/usr/local/lib/node_modules/grunt-cli
/usr/local/lib/node_modules/gulp
/usr/local/lib/node_modules/gulp-cli
/usr/local/lib/node_modules/hexo-cli
/usr/local/lib/node_modules/js-beautify
/usr/local/lib/node_modules/less
/usr/local/lib/node_modules/npm
/usr/local/lib/node_modules/protobufjs
/usr/local/lib/node_modules/tern
/usr/local/lib/node_modules/typescript
/usr/local/lib/node_modules/vue-cli
/usr/local/lib/node_modules/yo
npm ERR! extraneous: acorn@4.0.4 /usr/local/lib/node_modules/eslint/node_modules/acorn
npm ERR! extraneous: acorn-jsx@3.0.1 /usr/local/lib/node_modules/eslint/node_modules/acorn-jsx
npm ERR! extraneous: ajv@4.10.3 /usr/local/lib/node_modules/eslint/node_modules/ajv
.......

索性来个彻底的清理:

  • Global packages中,除了npm package,其它的package先全部删除
  • 安装cnpm,替代npm (你懂的),然后安装回所需的Global packages
1
2
$ # 删除npm之外的其它package
$ npm ls -gp --depth=0 | awk -F/ '/node_modules/ && !/\/npm$/ {print $NF}' | xargs npm -g rm

根据淘宝NPM镜像(https://npm.taobao.org/)安装指导,安装`cnpm`:

1
npm install -g cnpm --registry=https://registry.npm.taobao.org

原因分析

本地的node.js是使用Homebrew安装的,由于node版本更新,导致一些安装在global的package出现extraneous问题。修复方式是重新安装(或更新)有问题的package。

!!!此处敲黑板!!!

由于Homebrew管理的node会经常升级更新,并且cnpm默认会将package安装到当前运行版本的node安装文件夹之中,这个默认行为会在node再次升级后导致已安装的全局package失效。因此,我们需要手动修改npmprefix设置。通过修改~/.cnpmrc,增加如下一行记录:

1
prefix = "/usr/local"

此时检查cnpm的配置会发现prefix的默认值已经被覆盖:

1
2
3
4
5
$ cnpm -g config ls -l | grep "prefix"
prefix = "/usr/local"
; prefix = "/usr/local/Cellar/node/7.9.0" (overridden)
save-prefix = "^"
tag-version-prefix = "v"