cnpm能用npm install吗_你不知道的 npm

dac1af90eb178458235c39e0383516c9.png

npm 是 Node.js 官方提供的包管理器,它上手简单,但内部却隐藏着不为人知的一面。这篇文章我想说说 npm 几个比较容易混淆的地方,然后再说点小技巧。

dependencies 和 devDependencies

绝大部分小伙伴应该平时都用过他们,字面上来看前者主要用于列出代码运行起来时所必要的依赖,而后者则是只在开发阶段需要用到的依赖。

那么问题来了,什么才算是只在“开发阶段”用到的依赖呢?其实这个范围还是比较模糊的。我认为对于一个纯前端项目来说,测试工具、编译工具、语法检查工具都可以算这一类。而对于一个 Node.js 项目来说,可能这个范围会更加模糊一些,因为基本上除了测试工具之外,上面所说的几类依赖在开发阶段和部署阶段可能都需要用到。

OK,既然我们花了很大心思把两类依赖分开,那么对于 npm 来说两者有何区别呢?这一点可能是很多人忘记的:npm 并不会在默认的 npm install 中区分,而需要我们换成:

npm install --production

或:

NODE_ENV=production npm install

如果没有上面的方法来做,你就白区分了。

peerDependencies 和 optionalDependencies

peerDependencies 什么时候用呢?当你在写一个插件的时候。

比如说你正在写一个组件库,组件库可以看作是Vue或React的插件。虽然你的组件库离了这些UI库就运行不了,但考虑到用户在使用你的组件库时都是已经安装了UI库的,你将UI库写成 peerDependencies 即可。这么做有什么好处呢?对于 npm 来说,这意味着更清晰的依赖树关系,也意味着用户不会因为你的插件自动下载重复的依赖。

那么 optionalDependencies 呢?看起来和 peerDependencies 很容易混淆,但实际它的场合是当你可能会用到一个依赖作为可选插件时。

举例来说,如果你的项目需要做图片处理,但允许某些格式的处理插件在安装时缺失,那这些插件就可以写在 optionalDependencies 里。

npm-shrinkwrap.json 和 package-lock.json

如果一个项目只有package.jsonnpm install安装依赖时总是会按照语义化版本号来尝试安装最新的依赖。对于很多人来说这种行为是预期之内的,因为很多bugfix可以在第一时间囊括。

但对于核心业务,我们可能想要的是每次部署安装完全一致的内容,这时候我们就需要生成上面两者中的一个。那么这两个文件有什么区别呢?其实主要的区别只有一个:package-lock.json不会在 npm 包发布时包含,但npm-shrinkwrap.json则会。如果你真的把package-lock.json放在了 npm 包中,npm在其它项目中安装这个 npm 包时也不会理睬这个package-lock.json

npm官方认为绝大部分情况下你都应该用package-lock.json,除非你需要部署的是一个全局命令行工具——全局安装的包没有上层 npm 包来锁依赖,只能靠自己了。

学会使用 npm ci

可能绝大部分小伙伴在部署npm项目时只是单纯地运行npm install,但这其实可能会有坑:老版本的npm install并不完全遵循package-lock.json

于此同时,npm installnode_modules目录有各种假设,执行的效率也不怎么样。一个更安全、高效的选择是:npm ci。这个命令会先删除node_modules,然后再按照package-lock.jsonnpm-shrinkwrap.json安装依赖,绝无二心——哪怕和package.json相悖。

正确设置镜像

无论是作为一个拥有私有镜像的企业,还是作为一个墙内想用国内npm镜像的用户,设置镜像已经成了我们每天和npm共存的一部分。据我观察,大家常用的镜像设置方法往往如下:

alias cnpm="npm --registry=https://registry.npm.taobao.org"

又或者如下:

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

这两种办法都凑合能用,直到你发现你要和团队协作,而他们使用npm而不是cnpm。无奈的你可能选择把命令带着参数写进package.json中。但总是有不适合用参数的场景,比如已经有上游写死了npm install,我们该怎么办呢?

一种办法是使用npm config来进行配置:

npm config set registry "https://registry.npm.taobao.org"

但是有没有一劳永逸、可以嵌入脚手架的办法呢?使用.npmrc

npm支持在项目的根路径下增加一个名为.npmrc的文件,这个文件中可以配置 npm 在执行时的各项参数,和调用npm config set是一个效果:

registry="https://registry.npm.taobao.org"

这样无论是你可爱的同事还是持续集成的脚本,都能正确地使用镜像了。为了保险起见,我还建议大家加上disturl这个配置:

registry="https://registry.npm.taobao.org"
disturl="https://npm.taobao.org/dist"

这是因为某些原生模块在编译时node-gyp可能会用它下载额外的头文件。

更优雅地运行 npm 命令行

如果你的项目依赖了某个Node.js命令行,该如何调用呢?比较粗犷的一种玩法是先全局安装,然后再使用。比如依赖 mocha 的项目可能有这样的:

npm i -g mocha
mocha --recursive "./spec/*.js"

这种方式无法锁定mocha的版本,如果多个项目之间冲突就很尴尬了。退一步,把mocha作为devDependencies如何?npm 有个“隐藏规则”,如果一个 npm 包是命令行,那么它会建立一个“快捷方式”,于是就可以这样用了:

{
  "devDependencies": {
    "mocha": "^6.0.0"
  }
}
./node_modules/.bin/mocha --recursive "./spec/*.js"

在 Linux 和 macOS 上,这种方法已经足够好了,但是一旦你的项目还有 Windows 用户参与开发,这种写法还是有问题的:因为 Windows 的目录分隔符是反斜杠。

从 npm 5.2.0 开始,npm 会新增一个命令行工具: npx。无需额外进行安装,上面的package.json又可以直接写为老样子了,但在调用时我们这样用:

npx mocha --recursive "./spec/*.js"

舒服多了吧。

其实 npm 还有很多细节,比如 npm link 的正确使用方法以及 npm update 的实际语义等,有机会再和大家分享吧。

Photo by Sebastian Unrau on Unsplash

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值