Fuhui

包管理工具


反思之前的过程,一直没有试图跟上技术的发展。恍然觉得,其实技术比买股票更能让我找到快乐。新的技术越来越多,能做的便是,持续保持蜗牛锲而不舍的精神,慢慢爬!

首先感谢这篇文章2018 年了,你还是只会 npm install 吗?,让我重新开始审视包管理工具。因为在PHP开发中有Composer,在Go的开发中有glide。但却没有尝试思考它们背后的那些为什么。

npm包管理

我一直不理解package.jsonpackage-lock.json这两个文件的作用。直观上看,前者是我们项目所依赖的包,后者是各个包自身的明细依赖。但这样的设计却是经过多个版本迭代最终确定的形式。

当我们执行install或者update的时候,package-lock.json会根据nodemodules的更新而进行相应更新。当前就理解到这里,请看Composer

包的版本

包的版本号采用semver约束,由3个数字组成,格式必须为 MAJOR.MINOR.PATCH, 意为: 主版本号.小版本号.修订版本号。

约束还有一条:主版本号相同的升级版本必须提供向下兼容,但这仅仅是口头约束。测试版本的匹配,可以访问网址:https://semver.npmjs.com/

管理依赖

有时候,项目和项目之间存在引用依赖关系。比如将多个项目间共同使用的类在common项目下维护,然后其他项目project-1project-2分别引用项目common。当project项目变得越来越多时,每次新的项目都需要手动拷贝common代码。

可以将common做为一个包来管理。创建package.json文件,将common项目托管到git仓库。执行npm install git_url就可以将common作为依赖包进行安装了。

npm除了安装git仓库的代码,也可以安装本地的代码。

npm install file:local-package-path

版本管理

svn或者git只需要提交package.json, package-lock.json, 不需要提交node_modules目录。

每次升级或降级版本,执行如下代码,相应的package.jsonpackage-lock.json会自动更新:

npm install <package-name>@<version>

删除依赖包:

npm uninstall <package>

Composer管理

Composer生成的包管理目录叫vendor,它也是生成两个文件composer.lockcomposer.jsoncomposer.lock描述了项目的依赖以及其它的一些元信息。

composer.lock用来明确锁定安装包的具体版本信息,包证所有人安装的版本都是一致的。具体的原因在于:

  1. composer.json中指定的安装包版本,比如^2.0,只能确定该包的主版本号一定是2,当Composerinstall的过程中,具体安装了该包符合条件的哪个版本,是无法从.json中看出来的。
  2. 同理,还是上面的例子,如果一个同事,数月前执行install安装的版本是2.0.0,后来这个包在2版本下发布了一个小版本2.1.0。另一个同事后来执行install,很可能就安装成了2.1.0

综上所述,composer.lock用来保证安装包的一致性,避免安装到不同的版本包,给生产环境带来的不确定性。

install/update

install主要用来安装新包。当安装新包的时候,需要首先查看.lock文件是否存在,如果存在,安装.lock中指定的具体版本。如果不存在,直接安装。同时更新.json.lock两个文件。

update主要用来更新.lock中安装的包。随着时间的推移,.json中的包可能又发布了新版本,所以update就是用来检查.json中包的新版本,更新.lock文件用的。

我在使用的过程中,比较倾向于使用下面的单个包操作的方式:

php composer.phar update monolog/monolog [...]

版本管理

git环境中.json.lock都需要被提交的版本控制。vendor目录就不需要啦。

Go下的版本管理工具

glide

glidego的版本管理工具。其实glide也是参考composer设计的,所以上面对composer的说法也同样有效。

在项目开发中也仅需要对 glide.yamlglide.lock 进行版本控制,vendor目录可以忽略掉。

注:vendor目录默认会在项目下生成。需要特别注意的是:go的项目必须在gopath路径下的src目录下。

govendor

另一个版本管理工具是govendor。它做的只是对包的管理工作,如果编译过程中缺少了引用的包,我们需要先执行go get下载该包,然后通过govendor add +external将包拷贝到vendor目录。

比较实用的指令:

# 外部包,即被 $GOPATH 管理,但不在 vendor 目录下
govendor add +e 

# 从线上远端库添加或更新标签或分支等于v1的依赖包
govendor fetch golang.org/x/net/context@=v1

# 本地存在vendor.json 时候拉取依赖包,匹配所记录的版本
govendor sync -v