Changesets 是一个用于 Monorepo 项目下版本以及 Changelog 文件管理的工具。目前一些比较火的 Monorepo 仓库都在使用该工具进行项目的发包例如 pnpm、mobx 等。github 仓库为: https://github.com/atlassian/changesets,在 github 上有大约 2k 的 star。
目前笔者组自研的 Monorepo 发包方案基于该方案进行二次开发,替代 lerna 成为工程化团队内部统一的发包方案,并在其它团队也取得了不错的落地效果,其中包括之前关于 pnpm 的个人文章中提到的 Tiktok FE 团队,另外也包括目前字节开源出来的 modern.js 仓库:
在这篇文章中,将会介绍 changesets 工具是如何来完成 Monorepo 仓库中项目包版本的管理、一些基本的命令使用以及原理、同时还会介绍一些缺陷以及目前可以优化的一些点。
在之前的文章中,有介绍过基于 lerna 发包方案的源码解析。同时笔者组自研的 Monorepo 工具中,早期版本中也是采用了 lerna 这一套的发包方案,但随着在用户中的推广以及使用,这套方案随之带来了不少问题:
ignoreChanges
不能做到文件的完全忽略,存在优先级问题lerna version
根据 commit 以及 tag 更新出来的包版本不符合预期lifecycle scripts
经常命中一些用户自定义的 script(例如 publish
等)基于以上这些缺点,包括 lerna 本身的使用成本以及冗余的代码设计,加上目前 lerna 本身停止维护,因此在调研之后,我们将自研 Monorepo 工具中发包方案逐步替换为了 changesets。
在前面我们讲过了 changesets 的作用,changesets 主要关心 monorepo 项目下子项目版本的更新、changelog 文件生成、包的发布。一个 changeset 是个包含了在某个分支或者 commit 上改动信息的 md 文件,它会包含这样一些信息:
Changesets 工作流会将开发者分为两类角色,一类是项目的维护者,还有一类为项目的开发者,两者的职责可以通过如下流程图很简洁的表示出来:
根据上图, changesets 的工作流程是这样:开发者在 Monorepo 项目下进行开发,开发完成后,给对应的子项目添加一个 changesets 文件。项目的维护者后面会通过 changesets 来消耗掉这些文件并自动修改掉对应包的版本以及生成 CHANGELOG 文件,最后将对应的包发布出去。
以上就是一个简单的 changesets 工作流,当然这些工作流会对应到具体的 cli 命令以及 config 配置中去,下面我会基于此工作流介绍一些关于 changesets 最常用的几个子命令以及使用原理。
如果要使用 changesets,需要先安装其 CLI 工具,通过 pnpm install @changeset/cli
安装就行。安装之后,就可以按照下面的一些命令开始使用了。
该命令为初始化命令,通过执行 changeset init
,可以在项目根目录下生成一个 .changeset
目录,里面会生成一个 changeset 的 config 文件,可以参考 pnpm 目前项目的根目录:
该命令原理相对简单,执行的时候通过 fs 将对应配置文件写到目录下就行,关于 config 中的具体配置描述可以参考官方文档。init 初始化出来的为默认配置,一般不需要用户去做过多的修改。
add
在 changesets 中算得上比较关键的命令之一了,它会根据 monorepo 下的项目来生成一个 changeset 文件,里面会包含前面提到的 changeset 文件信息(更新包名称、版本层级、CHANGELOG 信息)。
还是以 pnpm 该项目作为例子,例如在 pnpm 仓库下执行 changeset add
会出现一系列 Prompt 问题:
会让我们选择本次 changeset 需要发布的包,这些包名都是 Monorepo 项目下的子包,changesets 内部通过
getPackages()
这一方法得到 Monorepo 项目下子项目信息,该方法的具体实验可以参考 changesets 下面一个叫做 @manypkg/get-packages
的包。方法本质上是通过读 Monorepo 下所有子项目的 package.json
然后构建出一个依赖图出来,changesets 可以根据该结果得到需要进行发包流程的项目,可以说整个 changesets 项目本身都会基于底层这个方法来进行构建,有点类似于一般 Monorepo 工具中的 graph 构建。
这里同时会通过封装的 git diff
命令检查出本次 commit 修改了的包名称,不过即使是没有修改的包,用户其实也是可以进行选择的,这里不同于其他 Monorepo 发包工具的区别在于更多的修改权限在用户的手里。
之后选择了想要发布的包之后,后面会选择到想要更新包的版本层级,例如这里我选择了 patch 级别,按照 semver 的规范,这里选择的包为
@pnpm-private
,在填完 summay 之后,后面会生成一个文件名称随机的 changeset 文件,如图所示:
这里文件的名称是通过一个叫做
human-id
的库生成的,具体可以在 npm 上查看,但实际上这里用户也是可以自行修改文件名称的,这里并没有太大的关系,也可以修改文件里面的 CHANGELOG 的信息。
这个文件本质上是做个信息的预存储,在该文件被消耗之前,用于是可以自定义修改的。随着不同开发者的迭代积累,changeset 文件是可以在一个周期之内进行累积的。例如 pnpm 现在下面就积累了一些 changeset 文件:
如果有信息相同,只是 CHANGELOG 描述不同的 changeset 文件,在消耗这些文件的时候是会被合并处理的,即对应包的 version 并不会被升级多次。
version
这个命令这里可以当作 bump version 来理解,这里本质上做的工作是消耗 changeset 文件并且修改对应包版本以及依赖该包的包版本,同时会根据之前 changeset 文件里面的信息来生成对应的 CHANGELOG 信息。version 的源码流程具体为:
这一步的核心步骤主要在依赖于 changesets 本身项目下的两个库,分别为
@changesets/assemble-release-plan
和 @changesets/apply-release-plan
,其中 assembleReleasePlan
主要是通过读生成的 changesets 文件然后分析出需要更新的包版本以及其依赖关系,然后将读出来的待更新结果给到 applyReleasePlan
中去,在 applyReleasePlan
中则会根据相应的信息修改掉包版本、消耗掉 changeset 文件、同时更新掉 CHANGELOG 文件(如果没有就新生成一个)。
例如现在在 pnpm 仓库的根目录下执行一次 changeset version,那么就会根据上面的流程得到这样的结果:
对应的 changeset 文件被消耗,然后对应子项目的 CHANGELOG 以及版本发生变更,当然改完后不满意用户还可以手动对 changelog 进行修改。自动修改的 changelog 信息如下:
changesets
还提供了一些其他的命令,这里我就不再一一对其介绍,这些命令其实相对比较好理解并且实现上没有特别让人难以理解的地方。例如用户如果要发一个 prelease 的包版本(例如 beta、alpha 版本),那么就可以使用 changeset pre
命令,然后再结合 version 命令去进行版本的 bump。
如果用户想查看当前的 changesets
文件消耗状态,那么可以使用 changeset status
命令。
发包的 changeset publish
本质上就是对 npm publish
做了一次封装,同时会检查对应的 registry
上有没有对应包的版本,如果已经存在了,就不会再发包了,如果不存在会对对应的包版本执行一次 npm publish
。
笔者在前面其实有提到过目前团队开发 Monorepo 工具时,并没有直接接入 changesets 这套方案,而是通过直接 fork 该仓库进行修改,主要在于这套方案目前在一些使用场景下确实存在许多问题。
在前面有提到 add 这一命令生成出来的 changeset 文件名称是随机的(通过 human-id 这个库生成),那么在一个快速迭代的 Monorepo 开发场景下。例如笔者组 Monorepo 项目,每周会大概产生 20+ 的 changeset 文件,而这些文件名称又是随机的,非常不便于用户去进行管理和辨别。
因此笔者在 fork 该项目之后,通过修改了 @changesets/write
这一部分代码,使得生成的 changeset 文件能够按照分支名+用户名+id 的形式显示出来,便于不同的开发者对自己的 changeset 文件进行筛选。
例如 add 命令无法指定特定的包,而只能通过前面 getPackages()
方法得到所有的子项目名来进行选择,如果一个项目下存在好几十个子项目的话,找具体的项目就是一件很费成本的事情。
不过 add 命令至少会通过 git diff
来筛出修改的子包名称,这样在一定程度上减少了用户去找项目的成本,但是 version 命令因为没有提供对应的筛选功能,导致在一些场景下,用户只想消耗特定的 changeset 文件去更新特定包是无法完成的。
因此笔者在 fork 该项目之后,通过其与 pnpm 的 filter 机制(参考文档: https://pnpm.io/filtering)结合,使得整个工作流能够被用户进行自定义筛选。
使用 changesets 如果想发一些测试版本的包,需要反复执行 changeset pre enter
、changeset pre exit
以及 changeset version
等命令,整个流程上是很繁琐的。实际上在自行维护的过程中,这些琐碎的流程可以集合到一个命令中来完成的,并不用消费如此大的成本。
这一点其实也算是支撑笔者自己 fork 源码重新搞一套的一个重要理由,目前该项目处于长期没有 PR 合并的一个状态,近半年来合并的 pr 都是一些简单的文档修改而没有实质性的功能进展:
同时 changesets 本身的文档还是比较欠缺的,例如一些常见的 FAQ 文档目前还是处于 TODO 的状态。
不过好消息是最近作者已经开始活跃起来,并回复了大量的 issue ,期待能在不久之后重新将整个项目运作起来。
目前的 changesets 方案整体而言在 Monorepo 项目下还是挺适用的,而且整体架构上而言并没有特别大的技术难点,主要难点在于 version bump 这一部分。
笔者认为该方案最大的优点在于提供了很大的自主权在用户手中,在复杂的业务场景下能够做出一些合适的调整,例如用户可以自行修改 changeset 文件、changelog 文件、甚至是 bump version 后不满意的版本。
相比较于 lerna 提供的比较理想化的方案而言,changeset 本身是一套泛用性很强的方案,而且比较适合当下 Monorepo 工作流场景下的一些运作方式,虽然本身还存在着不少的缺点。
期待作为目前不少 Monorepo 项目正在使用的发包方案,未来 changesets 能越来越流行~
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/QKqaO3U1gzwWb2sDiF4cLQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。