如何将 Node.js 应用程序迁移到 Deno 2.0
Deno 是一种流行的 JavaScript 运行时,它最近推出了 2.0 版,其中包含一些新功能、错误修复和对现有功能的改进。在此版本中,Deno 提供了与 npm 模块的完全兼容性、广泛而稳定的标准库以及用于几个常见 JavaScript 相关任务的内置功能。所有这些都使现在成为将您的应用程序从 Node.js 迁移到 Deno 并利用其功能的好时机。
在本文中,我们将逐步了解如何将使用 Node.js 的现有应用程序迁移到 Deno。
我们将看到以下内容:
为什么现在是迁移的好时机
Deno 试图解决开发人员在使用 Node.js 时面临的许多常见问题。使用 Node,您需要安装外部包来格式化和检查代码,因此您最终会在每个项目目录中获得所有依赖项的副本。
另外,如果您想将代码转换为独立可执行文件,则需要另一个软件包工具链来实现这一点。许多开发人员面临的另一个常见问题是,当尝试使用 TypeScript 时,他们必须设置和配置“tsc”,并且可能需要一个打包器来将 TS 编译为纯 JS。
虽然可以说为所有这些提供单独的和独立的软件包是一件好事,但对于很多开发人员来说,所有这些只是他们在开始处理实际项目代码之前需要采取的中间步骤。
Deno 为这些问题提供了解决方案和内置工具,可以减少设置和配置这些工具的麻烦。
另一个现在是切换的好时机的原因是,随着 2.0 版本的发布,Deno 与 Node API 和 npm 包完全兼容。这意味着你可以将整个设置逐步转换为 Deno,而不是一次性进行昂贵的迁移。
而且,如果您发现任何问题,可以更轻松地撤消并返回到原始设置。
迁移示例
出于本文的目的,我们将使用一个简单的项目启动器来演示要点。虽然它肯定不像真实项目那么复杂,(作为开发人员,我们当然可以在我们的项目中做一些非常复杂的事情),但它仍然是展示如何规划和执行迁移的好方法。
我们将使用 SvelteKit 演示模板。
要进行设置,请运行“npx sv create deno-migrate-test”,然后选择以下选项:
命令完成后,您可以“cd”进入目录,然后运行“npm run dev”来启动开发服务器。然后您就可以探索应用程序前端了。
从 npm 切换到 deno
迁移过程中的第一步也是最简单的一步就是停止使用“npm”,改用“deno”。您可以使用“deno task` 而不是 `npm run` 来运行你的 npm 脚本,它们将像 npm 一样执行。
对于我们的示例,您可以运行“deno task dev”而不是“npm run dev”来像以前一样启动开发服务器,并检查前端。如您所见,前端可以像以前一样工作。
请注意,如果您直接从脚本调用“node”,例如“node some-script.js”,Deno 将启动 Node 来执行该脚本。您还可以用“deno some-script.js”替换此类脚本,以使用 Deno 运行它们。
然而,这需要进行一些更改,例如将扩展名更改为 `.cjs` 或向 `package.json` 文件添加 `"type" : "commonjs"`,因为 Deno 默认假定 `.js` 文件是模块文件并使用带有 `import` / `export` 语句的 es6 语法。
您还需要添加 `-A` 标志以允许脚本的所有权限。如果您不想在此阶段进行这些更改,您可以暂时保留节点并稍后更改它们。
此时,您还可以使用 Deno 从 CI 设置中替换 npm,以使用“deno install”安装依赖项,并运行上述命令。
完成此操作后,您就可以开始在 CI 和本地开发中使用 Deno,并观察一段时间是否在日常开发中遇到任何问题。此时,如果您发现任何问题,只需切换回 Node/npm 即可轻松回滚。
切换到 Deno 工具
一旦您习惯使用 Deno 进行本地开发,并且它在您的 CI 设置中运行,下一步就是用 Deno 的内置工具替换一些开发人员工具。此步骤需要对您的设置和配置文件进行一些更改,但通过版本控制,您可以轻松地撤消它。
第一个要替换的工具可能是格式化程序。Deno 有一个内置的格式化程序,其中包含一些用于格式化代码的默认设置。您可能已经设置了一些格式化程序,例如 prettier,并且已经根据您的要求进行了配置。
Deno 还允许配置格式化程序,如果你想查看它将引入多少更改,可以运行 `demo fmt` `--unstable-component` `--check`。这将显示将进行的格式更改,以确认 Deno 的格式化程序。
有几个配置选项可用于配置此处看到的格式化程序,但总的来说,格式化程序是相当有主见的。
我个人对格式化程序的看法是,只要它可以在保存时自动格式化并且可以轻松设置,它就是一款好用的格式化程序。虽然有几种不同的口味偏好,但重要的是每个人都遵守相同的格式化规则,并且格式化的代码易于阅读和理解。
从这个意义上讲,虽然 Deno 可能没有提供像 prettier 那样多的配置选项(prettier 提供了很多扩展配置的选项),但它仍然是一个很好的格式化程序。如果你对更改感到满意,你可以使用它,或者你可以继续按原样使用现有的格式化程序。
类似地,你可以使用 `deno lint` 来替换你的 linter,例如 `eslint` 。与格式化程序类似,它与 `eslint` 有几个不同之处。但是,与 `deno fmt` 相比,它提供了许多常见的 lint 并提供了更多的配置选项。
您可以在此处查看它们,但与 ESLint 规则和预先存在的配置相比,它们仍然有限。如果您不满意,您也可以继续使用现有的 linter。
最后,另一个需要考虑替换的工具是测试工具。在我们的示例中,它是 Vitest,但您可能正在使用 Jest 或 Mocha 进行测试。这需要对代码进行最多的更改才能完全迁移到 Deno。
Deno 直接从其标准库中提供了内置测试工具以及断言和存根支持。您可以查看 https://jsr.io/@std/testing 以获取有关所提供选项的更多详细信息。
需要注意的一点是,Deno 还支持通过 Chai/Mocha 运行断言,因此您可以逐步将测试从现有的更改为 Deno。
一种方法是将测试文件分成两个目录——一个目录包含现有测试,另一个目录包含迁移到 Deno 的测试。然后,你可以逐个文件甚至逐个测试用例将测试迁移到 Deno,同时,你可以运行所有文件以保持覆盖率,不让任何错误溜走。
完成迁移后,您可以删除原始文件,而如果在迁移测试时发现任何重大问题,您可以简单地恢复到现有测试,而不必使用 Deno。
集成 Deno 的主要功能
一旦您开始使用 Deno 进行日常开发和生产,并且发现您对切换感到满意,并且工具或 CI 没有重大问题,您就可以开始在您的代码库中加入 Deno 的一些主要功能。
这将是一次重大改变,并且可能还需要对代码文件进行大量更改。但是,与其他步骤一样,仍有办法缓慢、分部分地完成此操作。
您可以首先使用 Deno 的功能直接编译和运行 TypeScript 代码,而无需“tsc”或其他软件包。您可以将“tsc”编译器配置从“tsconfig.json”移动到“deno.json”文件的“compilerOptions”。在我们的示例项目中,配置使用“extends”来扩展根配置。
但是,Deno 尚不支持此功能,因此您必须复制该配置并手动合并。完成后,您可以通过直接在 `.ts` 文件上调用 Deno 来替换使用 `tsc` 命令。
如果您尚未在项目中使用 TypeScript 但有兴趣这样做,您可以保留现有的 JS 文件并在 TypeScript 文件中添加新功能,因为 Deno 允许运行纯 JS 和 TS 而无需任何额外配置。
一旦您确信设置正常运行,如果您想使代码库同质,您也可以开始将现有代码转换为 TypeScript。
另一个需要更新的地方是 JS 文件中的导入和导出。Deno 默认允许“import”和“export”语句,并将文件视为模块。以前,您可能已将“type”:“commonjs”添加到“package.json”或将扩展名更改为“.cjs”,以便运行使用“require”语句的 JS 代码。
现在,你可以将 `require` 语句替换为 `import … from` `'…'` 语句。这样,你还需要为 node 标准库包添加 `node:` 前缀,并且可以为 npm 包添加 `npm:` 前缀。
这将是开始使用“jsr”(Deno 的首选包注册表)来导入 Deno 特定包的好时机,并开始使用 Deno 的标准库而不是 Node 的标准库。
Deno 的标准库在 2.0 版本中已经稳定下来,并提供了许多需要 Node 中外部包的功能,例如处理 yaml 或 csv 文件、常见的数据结构和集合、用于处理 cli 选项的 cli 模块、以及用于等待和去抖动等操作的异步模块等。您可以简单地将这些函数与 import 语句一起使用,然后在您的代码中使用它们。
import { debounce } from "@std/async/debounce";
您现在可以开始使用的 Deno 的一个主要功能是锁定允许应用程序的权限。从 Node 切换到 Deno 时,我们使用 `-A` 标志授予对代码的所有权限访问权限,只是为了让事情顺利进行。
但是,现在我们在转换上投入了更多,我们可以具体看看我们的代码需要哪些权限,重要的是我们想要允许哪些权限,并且只授予这些权限。
这样,我们不仅可以更好地了解我们的代码与系统其余部分的交互,而且还可以防止代码的意外或恶意访问,这可能会损坏开发人员的系统或泄露潜在的敏感信息。
高级用例:编译为二进制文件
Deno 的新功能之一(也是高级用例)是将 JavaScript 代码编译为独立可执行文件。这对于轻松分发代码非常有用 — 您只需共享一个文件,而不必共享所有代码和配置,并且您也不需要用户在其系统上安装 Deno。
虽然对于我们示例中的前端代码来说,这没什么用——最终的编译提供了需要服务器才能提供的 HTML-CSS-JS 文件。但是,对于 cli 应用程序或服务器应用程序来说,这非常有用。
使用它的基本方法是运行“deno compileentry-point`。这将分析您的 JS 文件,找出您的导入,并使用 JS 解释器将它们汇总为单个二进制文件。如果需要,这还会将 `node_modules` 与其捆绑在一起,因此生成的二进制文件的大小可能非常大。
结论
Deno 有很多很棒的特性,2.0 版本提供了对 npm 包和标准 Node 库的完全兼容,同时稳定了自己的标准库,提供了大量 API,保证了稳定性和可维护性。
通过它提供的优秀工具,如果您在使用 Node 时遇到一些痛点,或者只是想利用 Deno 的功能,那么这是一个考虑将您的 Node.js 应用迁移到 Deno 的好时机。
话虽如此,Node 已经存在很长时间了,并且拥有庞大的项目生态系统,因此它不会很快消失。因此,逐个迁移应用程序(甚至保留部分 Node.js)以使用 Deno 的功能是有意义的。由于 Deno 与 Node 兼容,这是一个兼顾两全其美的可行选择。
仅 200 秒✔️ 监控生产中失败和缓慢的网络请求
部署基于 Node 的 Web 应用或网站很容易。但确保 Node 实例继续为您的应用提供资源才是难点所在。如果您希望确保对后端或第三方服务的请求成功,请尝试 LogRocket。

LogRocket 就像是网页和移动应用的 DVR,可以记录用户与应用交互时发生的所有事情。您无需猜测问题发生的原因,而是可以汇总和报告有问题的网络请求,以快速了解根本原因。
LogRocket 会对您的应用进行工具化,以记录基准性能时间,例如页面加载时间、第一个字节的时间、慢速网络请求,还会记录 Redux、NgRx 和 Vuex 操作/状态。开始免费监控。