我们开发者工具团队是 TypeScript 的忠实粉丝,因此 DevTools 中的新代码都是使用 TypeScript 编写的,我们正在大规模迁移整个代码库,以便使用 TypeScript 进行类型检查。如需详细了解此次迁移,请参阅 2020 年 Chrome 开发者峰会上的演讲。因此,我们也考虑将 Puppeteer 的代码库迁移到 TypeScript。
计划迁移
在规划迁移方式时,我们希望能够分阶段推进。这样可以降低迁移开销(您每次只处理代码的一小部分),同时也降低风险。如果某个步骤出现任何问题,您可以轻松将其还原。Puppeteer 有许多用户,如果发布版本有问题,会给许多用户带来麻烦,因此尽量降低破坏性更改的风险至关重要。
我们还很幸运,Puppeteer 提供了一组强大的单元测试,涵盖了其所有功能。这意味着,我们可以确信自己在迁移过程中不会破坏代码,也不会对 API 进行更改。迁移的目标是让所有 Puppeteer 用户都不会察觉到迁移,而测试是该策略的重要组成部分。如果测试覆盖率不佳,我们会先添加测试,然后再继续迁移。
在未进行测试的情况下执行任何代码更改都很危险,但更改整个文件或整个代码库的更改尤其危险。在进行机械更改时,很容易遗漏某个步骤,而且在很多情况下,测试发现了实施者和审核者都忽略的问题。
我们在前期花费了一些时间来设置持续集成 (CI)。我们注意到,针对拉取请求运行的 CI 不稳定,并且经常失败。这种情况发生得太频繁了,以至于我们养成了忽略 CI 并合并拉取请求的习惯,假定失败是 CI 上的一次性问题,而不是 Puppeteer 中的问题。
经过一些常规维护和专门花时间修复一些常规测试 flakiness 问题后,我们让其进入了更稳定的通过状态,从而能够监听 CI 并了解失败是否表示存在实际问题。这项工作并不光鲜,而且看着无休止的 CI 运行令人沮丧,但鉴于迁移会向我们的测试套件发出大量拉取请求,确保测试套件可靠地运行至关重要。
选择并提交一个文件
至此,我们的迁移已准备就绪,并且有一个强大的 CI 服务器,其中包含各种测试来为我们提供保障。我们有意选择了一个小文件进行迁移,而不是深入研究任意文件。这项练习非常有用,因为它可以让您验证即将执行的计划流程。如果此方法适用于此文件,则说明您的方法有效;如果不适用,您可以重新开始。
此外,逐个文件进行更改(并使用常规 Puppeteer 版本,以便所有更改不会在同一 npm 版本中发布)可降低风险。我们选择了 DeviceDescriptors.js
作为第一个文件,因为它是代码库中最简单的文件之一。完成所有这些准备工作并进行如此小的更改,可能会让人感到有些失望,但我们的目标不是立即进行重大更改,而是要小心谨慎地逐个文件进行更改。在验证此方法时花费的时间,肯定会在迁移过程中遇到更复杂的文件时节省时间。
证明模式并重复
幸运的是,对 DeviceDescriptors.js
的更改成功纳入了代码库,并且方案也按预期发挥了作用!至此,您已经准备好全力以赴,这也是我们所做的。使用 GitHub 标签是将所有拉取请求归为一组的绝佳方式,我们发现这对跟踪进度很有帮助。
先迁移,然后再改进
对于任何单个 JavaScript 文件,我们的流程如下:
- 将文件从
.js
重命名为.ts
。 - 运行 TypeScript 编译器。
- 解决所有问题。
- 创建拉取请求。
这些初始拉取请求中的大部分工作都是为现有数据结构提取 TypeScript 接口。在我们之前讨论的用于迁移 DeviceDescriptors.js
的第一个拉取请求中,代码从以下代码变为:
module.exports = [
{
name: 'Pixel 4',
… // Other fields omitted to save space
},
…
]
变为:
interface Device {
name: string,
…
}
const devices: Device[] = [{name: 'Pixel 4', …}, …]
module.exports = devices;
在此过程中,我们检查了代码库中的每一行代码,以查找问题。与任何使用了几年并随着时间推移而不断发展的代码库一样,总有一些方面可以重构代码并改进现状。特别是在改用 TypeScript 后,我们发现在某些地方,稍微重构一下代码就能让我们更依赖于编译器,并获得更好的类型安全性。
与直觉相反,不要立即做出这些更改,这一点非常重要。迁移的目标是将代码库转换为 TypeScript,在进行大规模迁移的整个过程中,您应始终考虑导致软件和用户出现故障的风险。通过尽量减少初始更改,我们将此类风险降至最低。合并并迁移到 TypeScript 文件后,我们可以进行后续更改,以改进代码以利用类型系统。请务必为迁移设置严格的边界,并尽量不要超出这些边界。
迁移测试以测试我们的类型定义
将整个源代码迁移到 TypeScript 后,我们就可以将注意力转向测试了。我们的测试覆盖率很高,但全部采用 JavaScript 编写。这意味着,他们没有测试我们的类型定义。该项目的一个长期目标(我们仍在努力实现)是通过 Puppeteer 开箱即用地提供高质量的类型定义,但我们的代码库中没有任何关于类型定义的检查。
通过将测试迁移到 TypeScript(按照相同的过程,逐个文件进行迁移),我们发现了 TypeScript 中的问题,否则就只能由用户来发现。现在,我们的测试不仅涵盖了所有功能,还可以对 TypeScript 进行质量检查!
作为负责 Puppeteer 代码库的工程师,我们已经从 TypeScript 中获益匪浅。结合我们大大改进的 CI 环境,这让我们在使用 Puppeteer 时提高了工作效率,并让 TypeScript 捕获了原本会进入 npm 版本的 bug。我们很高兴能够发布高质量的 TypeScript 定义,让使用 Puppeteer 的所有开发者也能受益于这项工作。
下载预览渠道
不妨考虑将 Chrome Canary 版、开发者版或 Beta 版用作默认开发浏览器。通过这些预览版渠道,您可以使用最新的 DevTools 功能、测试尖端的 Web 平台 API,并帮助您在用户发现问题之前发现网站上的问题!
与 Chrome DevTools 团队联系
您可以使用以下选项讨论与 DevTools 相关的新功能、更新或任何其他内容。
- 请访问 crbug.com 向我们提交反馈和功能请求。
- 在 DevTools 中,依次选择 More options > Help > Report a DevTools issue 以报告 DevTools 问题。
- 向 @ChromeDevTools 发送推文。
- 在 “开发者工具的新变化”YouTube 视频或 “开发者工具提示”YouTube 视频中留言。