如何在 Node 和 React 中更新几年前的过时项目?

2025-06-07

如何在 Node 和 React 中更新几年前的过时项目?

浏览旧的 Node.js 依赖项可能会令人困惑。在本文中,我将分享如何使用自定义工具在一个已有几年历史的存储库中解决这个问题,以及如何让您也能从我的经验中受益。

简而言之,使用dependency-time-machine
工具可以按时间顺序快速逐个更新依赖项。大多数依赖项与类似或兴趣爱好中的其他包兼容。 此工具旨在模拟典型的定期更新工作流程。



npx dependency-time-machine --update


过时的代码库

GTA SA

最近我加入了一个新团队,他们有一款很棒的产品,但代码库却非常老旧。所以我的首要任务是更新依赖项并进行修改,以便我们能够从 Node 16 迁移到 Node 18,最终迁移到 Node 20。部分代码仍然依赖于 Node 14。我最初的想法是使用ncuyarn upgrade-interactive更新所有补丁版本,因为如果软件包开发人员遵循语义版本规范,这些补丁版本应该不会造成任何破坏。但他们并没有这样做。

依赖无效

许多依赖项不仅“老旧”——这本身并非问题所在,而且它们与新版 Node 以及我们所需的其他功能不兼容。在执行此过程时,Node 16 已弃用,Node 18 即将进入维护阶段。如此老旧的代码库使得进一步开发变得困难,而后端部分也使其不安全且易受攻击。

依赖项管理不仅关乎盲目更新,还关乎何时使用或删除软件包,以及对长期技术债务的常识。
有时,依赖项的较新版本可能会引入重大更改、性能下降或其他问题。在更新之前,开发者应该检查更新日志,了解更新的影响,并且最好在部署更新之前在受控环境中进行测试。

随着时间的推移,某些依赖项可能会变得多余,或者可能会出现更好的替代方案。一个好的做法是定期检查项目的依赖项,以确定它们是否仍然符合项目需求。此外,如果某个软件包不再维护或存在已知漏洞,那么寻找替代方案或将其完全删除可能是明智之举。

过度依赖多种依赖项会导致技术债务。如果管理不善,这些债务会不断累积,使未来的变更或更新变得繁琐且风险高昂。在利用现有解决方案(依赖项)和潜在的长期成本之间取得平衡至关重要。

图片描述

回到案例本身。值得庆幸的是,团队编写了大量优秀的测试,包括单元测试、一些集成测试以及大量的端到端测试,因此每次更新后都能检查是否有问题。这时,我意识到我必须逐个检查依赖项,看看哪些依赖项与其他依赖项以及 SDK 兼容。

一些软件包存在幻像依赖。它们是间接依赖(但也不是对等依赖),预计会安装它们并在某些目录中可用。npm 自 v3 版本起,以及 Yarn Classic 版本将依赖项安装在 node_modules 的扁平结构中,并且仅嵌套子依赖项,因此幻像依赖项的问题在软件包结构发生变化之前一直存在。pnpm 是另一个软件包管理器,它将依赖项安装在隐藏目录中,并使用符号链接使其在 node_modules 级别可用。此外,它隐藏了所有子依赖项,从而尽早打破了幻像依赖项,留下了干净的 node_modules(在我看来,这很好)。

npm v2 与 v3

其他问题是 Node SDK 从 16 到 18 的变化。与此同时,Node 17 在开放 SSL 提供程序中引入了变化,这破坏了旧的 webpack 和 DNS 解析机制,从“by-default-ipv4”到“by-default-ipv6”,这破坏了一些后端和测试库的使用。

依赖时间机器

为了解决所有这些令人头疼的问题,我利用业余时间编写了一个名为dependency-time-machine的库,它可以检索 package.json 中列出的每个包及其版本的信息。然后,它会创建一个单独的时间线,用于确定哪个库最落后,接下来应该更新。

我发现在特定时刻编写的库与相似或更早时间跨度的其他库兼容。例如,在某个a@2.5.1b@1.3.0已经可用时发布的库,其兼容性比同一库但版本更高(例如,b@1.3.2晚一年发布的库)的兼容性更高a@2.5.1



npx dependency-time-machine --timeline


Enter fullscreen mode Exit fullscreen mode

此外,这复制了更新依赖项的自然过程。当你定期执行此操作时,你会将现有库与其他现有库进行匹配。因此,dependency-time-machine我们试图解决的主要问题是重建自然更新的过程。

因为这可能需要大量的工作,比如我的情况,我需要处理超过 200 个软件包!为了简化这个过程,我引入了一个工具,auto mode它可以在另一个依赖项发布之前找到下一个需要更新的依赖项,安装它并运行测试。如果测试通过,它会反复执行相同的操作。如果测试失败,它会停止,以便您可以仔细检查并修复代码库或测试。



npx dependency-time-machine --update --install --auto --install-script "yarn install" --test-script "yarn test"


Enter fullscreen mode Exit fullscreen mode

此外,如果您不想依赖自动模式,您可以以 JSON 格式打印时间线,并手动决定是否更新依赖项。其他选项允许您排除因某些原因不想更新的依赖项。

回到故事本身。虽然还是花了些时间,但至少我对流程更加确定,并且有了清晰的工作计划。毕竟,我编写了文档来描述流程,以便其他团队成员了解存储库的进展,并讨论了整个流程。部署过程非常顺利,期间只出现了一些小问题,因为大多数问题都得到了团队成员的积极帮助,并及早被发现。

依赖管理可能会很痛苦,但定期并耐心地进行,可以让我们未来的工作更轻松。希望这篇文章和工具能帮到大家 :)

文章来源:https://dev.to/meatboy/how-to-update-a-few-years-old-outdated-project-in-node-and-react-31jm
PREV
使用 Link 向 React Router 传递数据
NEXT
我从事开发工作 11 年了。我学到的 5 件事:不要用大炮打蚊子