npm install --global or --save-dev, it's a question

npm install --global or --save-dev, it's a question_第1张图片
npm

一句话

如果你需要安装的带有CLI的npm包被某个项目依赖,请尽量使用--save-dev而不要使用--global安装。

引子

在我们启动一个前端项目时,总会用到一些 npm 上的带有 CLI 的包(package),我们在命令行下把这些包当作全局的系统命令来使用。比如 babel-cliexpress-generatorbrowserify 等等。我们往往在需要使用它们时这样做:

npm install -g babel-cli

之后,我们就理所当然的使用它们了:

babel script.js -o script-compiled.js

可是,这样真的好吗?

你在这样做时,也隐隐约约感觉到,这或许有些“脏”(dirty),有点像是泛滥的全局对象。

剥开看看

这种感觉没有错,拿 OSX 举例来说,如果我们使用 npm bin -g 来查看npm的全局包都装到哪了,会得到这样的结果:

/usr/local/bin

这个目录是系统中用来存放需要本地全局使用的二进制可执行文件的地方,属于系统环境的一部分,往往不仅仅被某个或某些应用依赖。

问题在哪

我们将带有CLI的npm包分为两类(非等价类):

  • 工程级
  • 系统级

如果我们仅仅是在现在的(或将来)某个项目中打算使用它,那么这类包更偏向于 工程级。比如之前文中提到的 browserifybabel-cli

如果我们更需要将它作为系统中的应用,而不限于在某个 Node.js 项目中依赖它,那么这类包更偏向于 系统级。比如 作为Node.js版本管理器的n

更直接一点说,如果某个npm包不被任何项目或应用依赖,那么它即属于 系统级

对于工程级的npm包,如果我们进行全局安装,那么会带来两个问题:

  • 全局安装的包会作为系统环境的一部分,但同一系统下的不同项目可能对于其依赖版本不同。
  • 项目在迁移或更换环境时,没有显性的依赖表明新环境需要该npm包

如何解决

npm 提供了一种针对于开发过程中依赖的安装方法:

npm install --save-dev 

使用这种方法安装的包,会在 package.json中被显性指出在 devDependencies中:

{
  "name": "my_package",
  "version": "1.0.0",
  "dependencies": {
    "my_dep": "^1.0.0"
  },
  "devDependencies" : {
    "my_test_framework": "^3.1.0"
  }
}

但这还有一个问题,如果使用 npm install --save-dev 安装的包,如何在项目中使用CLI呢?

首先,通过 --save-dev 安装的包的可执行文件都被放到了项目中的 ./node_modules/.bin/ 中。所以,我们可以通过该目录执行需要本地运行的CLI命令,比如:

./node_modules/.bin/babel script.js -o script-compiled.js

更进一步,我们也可以把命令放入package.jsonscripts中,比如:

{
    ...
    "scripts": {
        "babel": "babel"
    }
}

因为npm会在执行时首先检查当前项目中的 ./node_moduels/.bin/ 目录,这样在执行时只需要输入:

npm run babel -- script.js -o script-compiled.js

注意,传递参数前需要加 --

另外,还可以把 ./node_modules/.bin/ 加入到系统环境变量 PATH 中,但这样只能在包含 node_modules 的项目目录下使用CLI命令。这种做法其实更加增多了项目对系统环境的隐性依赖,不推荐。

结论

古人有云:“两害相较,则取其轻”。相比之前全局安装,使用 --save-dev 安装的npm包,在执行CLI命令时的确会比较麻烦,但这样做的好处也是显而易见且更为重要的,而对于增加的使用成本,另有许多成熟方法可以解决。在我们使用npm时,对于 工程级系统级 的包的区分有时并不是那么明显,希望通过这篇文章能让大家意识到使用全局安装的意义,并在管理项目依赖时多一些思考。

参考

  • Babel CLI docs
  • Stackoverflow - How to use package installed locally in node_modules?
  • How to Solve the Global npm Module Dependency Problem

你可能感兴趣的:(npm install --global or --save-dev, it's a question)