node.js 中的npm模块版本管理

semver

npm 中的模块版本都需要遵循 semver 2.0 的语义化版本规则。

版本格式:主版本号.次版本号.修订号,版本号递增规则如下: 主版本号:当你做了不兼容的API 修改, 次版本号:当你做了向下兼容的功能性新增, 修订号:当你做了向下兼容的问题修正。 先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

然后基于语义化的版本,我们在选择版本的时候就可以对依赖进行版本的控制:

dependencies: { "express": "3.x", "debug": "*", "express-session": "~1.0.0", "connect-redis": "1.2.3" }

从例子中可以看到,有许多种选择版本范围的风格,可以在 semver in npm 上看到每一个不同风格的作用。 而在 node.js 的模块管理中,最常用到的几种是:

  • *: 任意版本
  • 1.1.0: 指定版本
  • ~1.1.0: >=1.1.0 && < 1.2.0
  • ^1.1.0: >=1.1.0 && < 2.0.0

其中 ~ 和 ^ 两个前缀让人比较迷惑,简单的来说:

  • ~ 前缀表示,安装大于指定的这个版本,并且匹配到 x.y.z 中 z 最新的版本。
  • ^ 前缀在 ^0.y.z 时的表现和 ~0.y.z 是一样的,然而 ^1.y.z 的时候,就会 匹配到 y 和 z 都是最新的版本。
  • 特殊的是,当版本号为 ^0.0.z 或者 ~0.0.z 的时候,考虑到 0.0.z 是一个不稳定版本, 所以它们都相当于 =0.0.z。

semver 的弊端

按照 semver 的规范:

  1. 所有的 breaking change 都需要升级主版本号。
  2. 向后兼容的新增功能可以只升级次版本号。

但是最终在实践过程中,许多包没有遵循该原则,或者是没注意破坏了该原则,导致:

  1. 新增功能带来了 breaking change
  2. 修复现有 bug 引入未知的 breaking change

由此引出了下一个话题:如何正确的选择依赖模块依赖范围。

如何选择依赖范围

node 模块

在编写 node 的模块的时候,模块自身可能会依赖一些 dependencies, 然而我们并不想每一次依赖的 模块有任何小的 bug fix 的时候就要重新更新一次依赖,因此会推荐对大部分的依赖使用 ~ 前缀, 这样可以保证可以享受到这些依赖模块的 bug fix,并且不需要更新自身的版本。同时,也不会引入 一些 API 变更导致的无法预料的错误。当然,如果对一些完全信任的模块也可以考虑使用 ^ 前缀。

see: koa

node 项目

然而在编写 node 的项目的时候,我们更加希望能够追踪到所有依赖的任何变动,因为项目也不会有 关于自身版本更新的烦恼,因此更加倾向于写死依赖的版本,这样如果有任何由于更加容易追踪 升级依赖导致的 bug。

see: koa-todo

如何选择发布模块的版本

看完编写过程中怎么样选择依赖的范围,回过头来看看,如果我们需要编写一个发布到 npm 的模块, 需要如何选择发布的模块的版本。

  1. 当刚开始开发这个模块,它的功能和 API 都会有较大的调整的时候,可以选择发布 0.0.z 版本。
  2. 而当一个模块的 API 基本已经成型,不过可能会有一些新的 API 增加的时候,可以选择发布 0.y.z 版本。
  3. 当一个模块的功能基本已经完全定下来的时候,可以选择发布 x.y.z(x >= 1) 版本。当模块发布到 npm 之后,就意味着已经正式准备好了,所以尽量把发布的第一个版本定为 1.0.0。
  4. 当修复了一些小的 bug 的时候,请升级 z 的版本号,这样可以让用户通过 ~ 和 ^ 前缀最快速的享受你的 bug fix。
  5. 当增加了新的功能的时候,可以选择升级 y 的版本号。
  6. 当变更会影响原有接口的情况下,起码要升级 y 的版本号,这样不会影响大部分依赖这个库的用户。
  7. 当重构了模块,从设计上就有很大不同的情况下,需要升级 x 版本号。

遵循这几条规则,这样用户在引入这个模块的时候就可以轻松的通过 semver 提供的验证机制来更轻松的使用你的模块。

时间: 2024-10-08 08:29:01

node.js 中的npm模块版本管理的相关文章

node.js中使用net模块创建服务器和客户端

1.node.js中net模块创建服务器(net.createServer) // 将net模块 引入进来 var net = require("net"); // 创建一个net.Server用来监听,当连接进来的时候,就会调用我们的函数 // client_sock,就是我们的与客户端通讯建立连接配对的socket // client_sock 就是与客户端通讯的net.Socket var server = net.createServer(function(client_soc

在node.js中使用mongose模块

对象与文档相对应 创建项目目录,用root进入 # mkdir /home/test/part9/ 直接# npm install mongoose,报错如下 ../node_modules/nan/nan.h:316:47: error: ‘REPLACE_INVALID_UTF8’ is not a member of ‘v8::String’ static const unsigned kReplaceInvalidUtf8 = v8::String::REPLACE_INVALID_UT

Node.js中的fs 模块

// file system 是node的文件处理模块 const fs = require('fs') const path = require('path') // 1. readFile 此函数用来异步读取文件,并在回调中可以获取读取文件结果 // 这个方法会将一个文件的全部内容都读到内存中,适合于体积小的文本,如果文件有数百MB大小,则建议使用stream let filePath = path.join(__dirname, 'test.txt') fs.readFile(filePa

Node.js权威指南 (12) - Node.js中的其他模块

12.1 使用dns模块解析域名 / 313 12.1.1 使用resolve方法将域名解析为DNS记录 / 313 12.1.2 使用lookup方法查询IP地址 / 315 12.1.3 使用reverse方法反向解析IP地址 / 316 12.1.4 dns模块中的各种错误代码 / 31712.2 使用punycode模块转换punycode编码 / 31812.3 使用os模块获取操作系统信息 / 32012.4 使用readline模块逐行读取流数据 / 323 12.4.1 创建 I

node.js第二天之模块

一.模块的定义 1.在Node.js中,以模块为单位划分所有功能,并且提供了一个完整的模块加载机制,这时的我们可以将应用程序划分为各个不同的部分. 2.狭义的说,每一个JavaScript文件都是一个模块:而多个JavaScript文件之间可以相互require,他们共同实现了一个功能,他们整体对外,又称为一个广义上的模块. 3.Node.js中,一个JavaScript文件中定义的变量.函数,都只在这个文件内部有效.当需要从此JS文件外部引用这些变量.函数时,必须使用exports对象进行暴露

记一次在node.js中使用crypto的createCipheriv方法进行加密时所遇到的坑

Node.js的crypto模块提供了一组包括对OpenSSL的哈希.HMAC.加密.解密.签名,以及验证等一整套功能的封装.具体的使用方法可以参考这篇文章中的描述:node.js_crypto模块. 本文重点介绍在使用createCipheriv方法时所遇到的坑.对应的解密算法createDecipheriv应该是一样的问题. 按照文档中的描述,createCipheriv方法接受三个参数:algorithm用于指定加密算法,如aes-128-ecb.aes-128-cbc等:key是用于加密

Node.js权威指南 (4) - 模块与npm包管理工具

4.1 核心模块与文件模块 / 574.2 从模块外部访问模块内的成员 / 58 4.2.1 使用exports对象 / 58 4.2.2 将模块定义为类 / 58 4.2.3 为模块类定义类变量或类函数 / 614.3 组织与管理模块 / 61 4.3.1 从node_modules目录中加载模块 / 61 4.3.2 使用目录来管理模块 / 62 4.3.3 从全局目录中加载模块 / 624.4 模块对象的属性 / 634.5 包与npm包管理工具 / 65 4.5.1 Node.js中的包

log4js-Node.js中的日志管理模块使用与封装

开发过程中,日志记录是必不可少的事情,尤其是生产系统中经常无法调试,因此日志就成了重要的调试信息来源. Node.js,已经有现成的开源日志模块,就是log4js,源码地址:点击打开链接 项目引用方法: npm install log4js 1.配置说明(仅以常用的dateFile日志类型举例,更多说明参考log4js-wiki): { "appenders": [ // 下面一行应该是用于跟express配合输出web请求url日志的 {"type": "

node.js中模块,require

在php,C++中都有命名空间的概念,命名空间主要是用来解决引入文件存在函数,类,变量重名的问题,在node.js中,没有命名空间这么复杂的概念,在node中,有模块的概念,也就是将功能性的代码都放在一起.然后引入,在本文件中使用.这种不会出现函数名,变量重名问题,在引入的模块中,都是以导入的方式注册的.看下面的例子: //circle.js var pi = 3.14; //计算圆的周长 exports.circle = function(r) { return 2 * pi * r; } /