我们将40万行代码从Flow迁移到了TypeScript

2022年2月21日 296点热度 0人点赞 0条评论

图片

【CSDN 编者按】哪种类型系统将主宰JavaScript的世界?不同时代有不同的答案。本文作者在选择Web生态系统用于构建的产品Factorial时,对比当时Facebook的Flow和微软的TypeScript,综合考虑选择了略胜一筹的Flow。但随着时间的推移,TypeScript开始在该领域展现主导地位。于是决定换框架,来看看他们是怎么做的吧。

原文链接:https://labs.factorialhr.com/posts/how-we-migrated-400k-lines-of-code-from-flow-to-typescript

本文 CSDN翻译,转载请注明来源出处。


作者 | Ferran Basora
译者 | 弯月  责编 | 章雨铭
出品 | CSDN(ID:CSDNnews)

在构建我们的产品Factorial之际,Web生态系统正在经历一场激战:哪种类型系统将主宰JavaScript的世界。两大主要竞争者分别是来自Facebook的Flow和来自微软的TypeScript。就功能而言,这两大框架似乎并没有太大区别,只不过Flow支持async/await和装饰器等不错的功能,所以略胜一筹。更不用说它与React都出自Facebook之手,因此在当时,它与React配合使用的效果更佳。

在Web(无论是前端还是后端)不支持类型检查的时代,将类型系统(无论是哪一种)添加到最小可行产品成为了代码质量和维护方面的及格线。最后,我们还是选择了Flow。

随着时间的推移,TypeScript开始在该领域展现出主导地位。TypeScript的发展更快、社区更大、拥有大量的类型库、拥有更好的插件和IDE支持,以及许多其他优势,例如在npm生态系统中的广泛采用,因此许多拥有类型的库都得以公开。

另一方面,我们深受Flow检查器无休止的分析和内存泄漏方面的折磨,尽管TypeScript检查器在性能方面的表现也差强人意,但它在配置方面的粒度与各种标志确实非常吸引人。于是,我们决定换框架。


图片

迁移的注意事项


在迁移方法的初步审查期间,为了确保迁移成功,我们列出了一组必须遵守的约束,其中包括:
  • 不能冻结代码。想象一下告诉开发团队:“我们要开始迁移大量的代码了,持续时间还不确定,你可不可以暂停一下手头的工作……”不太现实吧?停止开发会给项目带来太多风险。 
  • 保留 Git 历史记录源代码的信息远不止代码本身,还有每一行代码背后的历史记录。如果在代码迁移到过程中,这些历史记录丢失,就太可惜了。
  • 进行最终的迁移时,最好不要干扰现有的拉取请求。我们不希望代码迁移引发大量拉取请求方面的冲突和各种麻烦。 
  • 不能造成思维模式的混乱。许多教程在介绍JavaScript文件中使用TypeScript的功能时,都采用了渐进式的迁移过程。但是,我们不希望团队在思维模式方面出现混乱,即不知道在某个时间点使用哪种技术,并导致无法判断迁移何时结束。 
这些约束并非晦涩难懂,但是我们会竭尽所能遵守这些约束,并找出迁移需要面对的长期挑战。


图片

左右为难

 

在开始迁移代码之前,我们首先研究了其他团队,他们也面临着相同的挑战:将庞大的代码库从Flow(或JavaScript)迁移到TypeScript。我们做了很多研究,并在动手迁移代码之前总结了一些经验。

在代码迁移的策略方面,我们有两个选择:

  • 方法A:将大部分代码库都迁移过去,以尽可能减少思维模式混乱的问题。这就需要渐进式迁移,所以我们选择从没有依赖关系的文件夹开始下手。

  • 方法B:创建一个“一次性”脚本来迁移整个代码库。通过这种方法正确迁移代码的难度非常大,因为我们需要将Flow的每一行代码都自动地转换成TypeScript。

最后,我们决定混合使用这两种方法(吸取两家之长)。我们发现,代码库中有一大块代码与其他文件之间是解耦的,很适合作为迁移的首个目标,并验证在生产中使用Typescript的想法。令人惊讶的是,我们率先迁移了这部分代码,并成功交付了。我们证明了Flow和TypeScript可以并存。因此,我们对一次性交付其余源代码的信心大增。


图片

另一个困境:工具

 

  • Ts-migrate:这是我们找到的最出色的工具之一,来自Airbnb,它可以自动迁移JavaScript代码库,同时根据TypeScript语言服务器的输出来决定如何处理不符合规范的地方。但我们没有采用这种方式,因为我们需要将代码从Flow迁移到TypeScript,而不是从JavaScript到TypeScript,二者完全没有可比性。
  • Flow-to-ts:这是我们此次代码迁移采用的主要工具之一,来自可汗学院。该工具是此次迁移的基础,我们对这款工具充满了感激。稍后我们会进一步讨论为何当初选择了它。


图片

开始迁移

 

为了遵守上面提到的首要约束(避免代码冻结),我们想方设法将尽可能多地将安全代码合并到主分支中。所谓“安全代码”指的是将TypeScript的配置文件、输入定义等推送到代码库。

另一方面,我们在一个分支中写了一个bash脚本,其中包含了迁移的所有步骤。以下是该脚本中包含的迁移步骤:

  1. 运行一组自定义的JsCodeShift转换;

  2. 在Git上,将所有js和jsx文件重命名为ts和tsx;

  3. 针对上述所有代码运行flow-to-ts转换;

  4. 运行lint和格式化工具,检查格式;

  5. 运行tsc验证并查看不符合规范的地方。

自定义JsCodeShift转换

考虑到上述步骤,我们决定不断迭代,以逐步减少tsc检测出的规范违反的代码。对于所有重复出现的规范违反,我们尝试编写了一些JSCodeShift转换。我们大量使用ASTExplorer作为实验场所,来编写我们的自定义转换。由于我们的代码库是Flow,所以我们决定利用这个先天优势,自动调整与类型相关的代码,以简化flow-to-ts的转换。

在这一步中,我们编写了十多个自定义转换,然后同时执行所有转换。

module.exports = function (file, api, options) {  const fixes = [    transformation1,    transformation2,    transformation3,...  ]
return fixes.reduce((src, fix) => { if (typeof src === 'undefined') { return }
return fix({ ...file, source: src }, api, options) }, file.source)}

Git 重命名

根据bash脚本,下一步是文件的重命名。我们使用了git mv,尽可能保持Git历史记录:

find $@ -iname "*.js" | while read line; do git mv -- $line ${line%.js}.ts; done;find $@ -iname "*.jsx" | while read line; do git mv -- $line ${line%.jsx}.tsx; done;

这一步的工作很简单,很容易被忽略,但从长远来看却非常重要。

运行 flow-to-ts

在这一步中,脚本需要使用flow-to-ts包执行主要的转换。flow-to-ts是Flow项目的一个核心工具,它理解许多Flow的常见模式,这些模式可以确定地映射到Typescript。它的内部是一个巨大的 JSCodeShift 转换,但有一些预设的配置可以让该工具的使用更容易。

Lint和格式化

尽管flow-to-ts的底层使用了recast ,而且会尽可能地保留代码原来的格式,但在转换到过程中会新建一些代码。这些代码需要格式化,以匹配我们的内部规则。

这一步有点慢,但不可略过。尽可能保持代码原来的格式对于保留Git历史记录至关重要。

使用tsc进行验证和审查

有了这个脚本,完成迁移到最后一步就是解决其他非重复性的规则违反。老实说,这是最困难的一部分工作,因为我们必须逐一排查并解决。在这个过程中,由于代码库是Flow,所以我们可以不断地将类型修复推送到master分支,同时还不会影响到应用程序的行为。


图片

总结成功的经验

 

我们成功了!我们一次性将40万行代码从Flow迁移到了TypeScript!在这个过程中,我们积累了很多宝贵的经验。

  • 保持透明,持续沟通,以获得团队的支持。最糟糕的情况是,在没有取得每一位团队成员支持的情况下,开展大量的工作。我们建议,分享、参与和记录迁移的每一个步骤、里程碑和关键日期。

  •  在开始动手迁移代码之前,做好准备。这是一个漫长的过程,需要深入了解代码库。你可能会发现,为了完成最后一步的迁移,前面的有些步骤需要返工。举个例子,我们发现装饰器的使用会影响flow-to-ts的执行。

  • 仔细思考迁移后代码的情况,并提出正确的问题。迁移后的所有工具都准备好了吗?开放的拉取请求会影响迁移吗?迁移后是否会出现lint和格式的问题?我们在合并代码之前,就已经解决了这些问题。

  •  最好将所有与迁移相关的提交压缩为一个提交。这可以简化部署,如果出现意外情况,也很方便回滚。

图片

今后的打算

 

我们的TypeScript之旅并没有就此结束。事实上,这只是一个开始!在采用该语言几天后,我们决定启用编译器中的strict标志。对我们来说幸运的是,我们可以逐步完成这项工作,因为这些标志可以一个个添加。

此外,我们也在考虑其他工具和机会。例如,目前我们使用Webpack来构建应用程序,但我们已经开始考虑esbuild和swc,因为这两个编译器对 TypeScript的支持更好。

几个月前,我们也惴惴不安,不知道能否在前端代码库中使用TypeScript。我们分析了利弊,并为此次大规模的代码迁移制定了明确的计划。两周后的今天,我们团队实现了更快的交付,而且还大幅提高了代码质量。这不仅可以减少生产中的错误,而且还可以让客户更满意。

如果你也面临相同的困境,希望这篇文章对你有所帮助。

图片

新程序员003》正式上市,50余位技术专家共同创作,云原生和数字化的开发者们的一本技术精选图书。内容既有发展趋势及方法论结构,华为、阿里、字节跳动、网易、快手、微软、亚马逊、英特尔、西门子、施耐德等30多家知名公司云原生和数字化一手实战经验!

图片

图片

下月苹果“小春晚”,M2 芯片终于要来了?
Android 13 “鸡肋”?可它跑起了 Windows 11、Linux 发行版!
React、Angular、Vue霸榜,薪酬以50k-100k为主,JavaScript 2021年度报告正式发布!

45140我们将40万行代码从Flow迁移到了TypeScript

这个人很懒,什么都没留下

文章评论