开发者工具团队非常喜欢 TypeScript,以至于开发者工具中的新代码都是用它编写的,而且我们正在将整个代码库迁移到 TypeScript,以便进行类型检查。如需详细了解该迁移,请观看 Chrome Dev Summit 2020 上的讲座。因此,考虑将 Puppeteer 的代码库也迁移到 TypeScript 是非常合理的。
计划迁移
在规划如何迁移时,我们希望能够以小步快跑的方式推进。这样可以降低迁移的开销(您一次只需处理一小部分代码),同时也能降低风险。如果其中一个步骤出现问题,您可以轻松还原。Puppeteer 有很多用户,如果发布版本出现问题,会给很多用户带来麻烦,因此我们必须将破坏性更改的风险降至最低。
幸运的是,Puppeteer 具有一套完善的单元测试,涵盖了其所有功能。这意味着,在迁移过程中,我们可以放心地确保不会破坏代码,同时也不会对 API 引入任何更改。迁移的目标是让所有 Puppeteer 用户在不知不觉中完成迁移,而测试是该策略的重要组成部分。如果我们没有良好的测试覆盖率,则会在继续迁移之前添加测试。
在没有测试的情况下进行任何代码更改都是有风险的,但涉及整个文件或整个代码库的更改尤其危险。在进行机械性更改时,很容易漏掉某个步骤,而测试多次发现了实施者和审核者都漏掉的问题。
我们前期确实投入了时间来设置持续集成 (CI)。我们注意到,针对拉取请求运行的 CI 不稳定,经常失败。这种情况非常频繁,以至于我们养成了忽略 CI 并合并拉取请求的习惯,因为我们认为失败是 CI 上的一次性问题,而不是 Puppeteer 中的问题。
经过一些常规维护和专门的时间来修复一些常规测试不稳定问题后,我们让它进入了更加一致的通过状态,使我们能够听取 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 开发者工具团队
您可以通过以下方式讨论新功能、更新或与开发者工具相关的任何其他内容。
- 如需向我们提交反馈和功能请求,请访问 crbug.com。
- 在开发者工具中,依次点击 更多选项 > 帮助 > 报告开发者工具问题,报告开发者工具问题。
- 在 Twitter 上发帖并提及 @ChromeDevTools。
- 在 “开发者工具的新变化”YouTube 视频或“开发者工具提示”YouTube 视频中发表评论。