npm如何管理依赖包的版本

Node.js的依赖管理系统公认是非常先进的。这一篇文章来简单谈谈npm如何管理项目的依赖包的版本。

下文大多翻译自Express in Action一书第12章的相关内容

语义化版本号

npm默认所有的Node包都使用语义化版本号,英文叫做semantic versioning。这是一套指导开发人员如何增长版本号的规则,要求:

  • 每个版本号都形如1.2.3,由三个部分组成,依次叫做“主版本号”、“次版本号”和“修订号”
  • 当新版本无法兼容基于前一版本的代码时,则提高主版本号
  • 当新版本新增了功能与特性,但仍兼容前一版本的代码时,则提高次版本号
  • 当新版本仅仅修正漏洞或者增强效率,仍然兼容前一版本代码,则提高修订号

默认情况下,npm install --save下载的都是最新版本,并且会在package.json文件里登记一个最优版本号,其形式如下所示:

"dependencies": {
    "express": "^4.10.0",
    "ejs": "~2.3.2"
}

可以看到,最优版本号在数字之前多出一个“标记”。当以后使用npm install按照package.json的这一部分来下载依赖包时,^意味着所下载的包有可能会有更高的次版本号或者修订版本号,而~意味着有可能会有更高的修订版本号。

锁定依赖包的版本

如果所有的Node包都严格地符合语义化版本管理的规则,那么npm的最优版本号就能保证所下载的依赖包一定是与代码兼容的。但问题是我们无法保证这一前提,如果想要保证用户(或者其他开发人员)下载依赖包与我们的代码绝对兼容,那么可以用下面两种办法来锁定项目的依赖包的版本号。

回避最优版本号

最简单最快捷的方法,就是不使用最优版本号。对于已经记录在package.json里的版本号,只需把打头的^~标记去掉即可。而新安装依赖包时,则使用npm install --save-exact <package_name>或者npm install --save <package_name>@1.2.3,这样package.json里就不会出现最优版本的标记。

这个方法虽然简单,但是有个缺陷:无法锁定次级依赖的版本号(依赖包的依赖包,等等)。比如说你的项目依赖某个特定版本的Backbone.js,你可以按照上面的方法在package.json里去掉最优版本的标记:

"dependencies": {
    "backbone": "1.2.3"   
}

而这个版本的Backbone有自己的package.json,里面记录的依赖包使用的很可能还是最优版本号。比如Backbone依赖Underscore.js,你在开发时,npm为Backbone下载的可能是underscore@1.1.1,而当之后的某个时刻,Underscore有了更新,同一项目的开发人员或者你的包的使用者运行npm install时下载的可能就是underscore@1.2.0。大多数情况下,这不会有什么问题,但是万一真的不兼容(或者你就是想要绝对安全),那么就得使用更加复杂一些的方法了。

使用npm shrinkwrap命令

现在问题的关键在于如何锁定依赖之依赖的版本号。npm有一个命令来解决这个问题:npm shrinkwrap

比如说,你在开发某个Node项目时,进行到某个节点,一切都运行顺利,说明目前所有的依赖包(以及更底层的依赖包)和你的代码兼容得很好。这个时候,你就可以在项目文件夹下运行上面的这个命令。它会生成一个npm-shrinkwrap.json文件,记录目前所有依赖包(及更底层依赖包)的版本信息。这样当以后你(或者你的同事、你的用户)运行npm install命令时,npm首先会找npm-shrinkwrap.json文件,依照其中的信息来准确地安装每一个依赖包,只有当这个文件不存在时,npm才会使用package.json

在这之后开发的过程中,如果你想要更新某个依赖包,比如将Express从4.13.0更新到4.14.1,那么就只需npm install express@4.14.1;或者想要添加新的依赖包,比如Helmet,也只需npm install helmet。经过一段时间的测试与开发,当你确定这些新版本新安装的依赖包与自己的代码兼容后,就可以再次运行npm shrinkwrap命令来锁定依赖包的版本。

本地安装优于全局安装

npm安装依赖包时有两种模式:本地安装或者全局安装。本地安装表示该依赖包会被下载到当前项目的node_modules文件夹里,而全局变量则会把它安装到系统级别的目录里。比如用npm install -g typescript全局安装typescript这个包后,我们就可以在系统的任何位置使用tsc命令来编译TypeScript文件。这本身没有什么错,有些Node包的命令确实需要在任何位置都能使用,但全局安装依赖包也有隐患:使用你的应用的用户如果没有全局安装typescript怎么办?或者如果她所安装的版本不兼容怎么办?

所以,安装依赖包最好遵循以下实践:

  1. 尽量不全局安装依赖包,除非是typescript,grunt这种确实有需要的
  2. 所有的依赖包都应该本地安装,即使是那些已经全局安装过的

本地安装的依赖包,其命令都位于当前项目的node_module/.bin文件夹下。package.json文件的"scripts"部分所使用的依赖包命令都会先去这个文件夹寻找。

例如,你的package.json里有这么一段:

"scripts": {
    "build:js": "tsc"
}

那么,当你运行npm run build:js时,npm会先去当前项目的node_module/.bin里寻找对应的执行文件,如果你没有本地安装,才会使用全局级别的命令。

结语

以上就是对npm如何管理项目的依赖包版本的一个简单总结。主要涉及的知识点包括:语义化的版本号,最优版本号,两种锁定依赖包的方法,以及为什么本地安装依赖包会优于全局安装

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容