使用 Deno Compile 创建自包含可执行程序
自 Deno v1.6 版本以来,deno compile
命令使开发者能够将 JavaScript 和 TypeScript 程序转换为可在所有主流平台上运行的独立二进制文件——无需依赖项,无需额外安装。这具有重大意义
- 跨平台兼容性:分发一个无需 Deno 运行时或依赖项即可工作的单个二进制文件。
- 打包资源:将你的应用程序所需的一切都打包到二进制文件中,以便于移植。
- 简化的部署:将一个二进制文件发布到生产环境,减少复杂性。
- 改进的启动时间:与典型的服务器或运行时设置相比,启动速度更快。
自 Deno 2 以来,我们为 deno compile
引入了更多改进,例如 支持 npm 包、Web Workers、交叉编译、更小的二进制文件大小以及使用自定义图标的代码签名。 这些升级意味着你现在不仅可以编译脚本,还可以将完整的应用程序(如桌面游戏)直接编译为原生二进制文件。
在本文中,我们将探讨 deno compile
的独特之处、其工作原理,以及不同用例的示例,这些示例突显了它相对于生态系统中其他替代方案的优势。
🚨️ Deno 2 发布了。 🚨️
凭借与 Node/npm 的向后兼容性、内置包管理、一体化零配置工具链以及原生 TypeScript 和 Web API 支持,编写 JavaScript 从未如此简单。
deno compile
?
什么是 Deno 为 JavaScript 和 TypeScript 提供零配置工具链,因此你无需在编写任何代码之前拼凑不同的工具。deno compile
是一个子命令,可让你从 JavaScript 或 TypeScript 代码构建单个二进制文件。与 Node 的 8 步编译过程不同,deno compile
仅需一个命令。
此子命令允许你跳过安装要求,并在未安装 Deno 的系统上运行二进制文件,跨越 Windows、macOS 和 Linux 等平台。Deno 编译的二进制文件也针对大小进行了优化。如果你来自 Node,这种简洁性减少了在环境之间移动代码时的摩擦,尤其是在为不同的操作系统目标进行交叉编译时。
deno compile
的工作原理
虽然它被称为“compile”,但 deno compile
并非以传统意义上的方式编译 JavaScript。相反,它将你的 JavaScript 和 TypeScript 代码嵌入到一个特殊的 Deno 运行时二进制文件中,称为 denort
(“Deno runtime”的缩写)。
以下是执行 deno compile
时过程的概要:
- 下载精简版的运行时
denort
。 如果你正在为不同的操作系统进行交叉编译,则会下载该平台的denort
。 - 你的脚本以及任何依赖项都会捆绑到一个
eszip
文件中,这是一种用于序列化 ECMAScript 模块图的无损格式。 - 该捆绑包使用 Sui 注入到
denort
二进制文件中。
通过将捆绑包嵌入到可执行文件的某个部分,输出的二进制文件仍然可以进行代码签名。
示例
基本的自包含二进制文件
首先,让我们看看从 TypeScript 脚本创建一个单独的可执行文件是多么容易。
// main.ts
import open from "jsr:@rdsq/open";
await open("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
编译它非常简单,只需:
deno compile -A -o runme main.ts
这会输出一个可执行的二进制文件 (runme
),其中包含所有必需的依赖项。现在你可以在任何平台上共享此单个文件,而无需最终用户安装 Deno。
请注意,你可以在 deno compile
命令中传递选择性加入的权限标志,例如 --allow-net
。权限标志将保留在编译后的二进制文件中,从而为你的二进制文件的使用方式提供额外的安全层。
为 Windows 交叉编译
假设你想与 Windows 用户共享该应用程序。使用 --target
标志,你可以为其交叉编译 Windows 版本
deno compile --allow-all -o runme --target x86_64-pc-windows-msvc main.ts
现在你有了 runme.exe
,一个与 Windows 兼容的二进制文件。你甚至可以使用 --icon
标志添加自定义图标,以获得更精致的外观
deno compile --allow-all -o runme --target x86_64-pc-windows-msvc --icon icon.ico main.ts
代码签名
代码签名确保你的二进制文件经过验证且值得信赖,这对于软件分发至关重要。Deno 简化了这一点,即使在 macOS 上,你也可以像使用任何其他应用程序一样使用 codesign
。
让我们确认我们二进制文件的完整性
codesign --verify -vv ./runme
./runme: valid on disk
./runme: satisfies its Designated Requirement
我们编译的二进制文件已正确代码签名,可以发布了。
编译 NPM 包
当然,可以使用 deno compile
编译 NPM 包。这种方法非常适合对性能敏感的 CI 环境,或者当你需要工具的单个便携版本时。
例如,让我们在 npm 本身使用 deno compile
deno compile -A npm:npm
运行编译后的 npm
二进制文件很简单,甚至显示出性能提升。在测试中,Deno 编译的 npm 二进制文件比常规 npm 快约 1.9 倍
# hyperfine "./npm -v" "npm -v"
Benchmark 1: ./npm -v
Time (mean ± σ): 40.1 ms ± 2.0 ms [User: 37.7 ms, System: 5.3 ms]
Range (min … max): 38.9 ms … 51.8 ms 71 runs
Benchmark 2: npm -v
Time (mean ± σ): 75.2 ms ± 7.6 ms [User: 59.1 ms, System: 9.0 ms]
Range (min … max): 69.2 ms … 105.0 ms 40 runs
Summary
./npm -v ran
1.87 ± 0.21 times faster than npm -v
这种方法也适用于其他流行的 npm 工具,如 prettier
和 eslint
,为你提供更快、更便携的版本。
游戏和桌面应用
deno compile
还开启了将基于 Web 的游戏和应用程序捆绑为原生桌面可执行文件的潜力。例如,你可以将一个 HTML/CSS/JavaScript 游戏转换为一个二进制文件,该文件易于共享并在任何桌面上启动。
deno compile
捆绑 HTML 游戏的视频演示。看看这个 Flappybird 克隆版,它可以使用 Deno 编译成桌面应用程序
deno compile --unstable-ffi --env -o flappybird -A main.js
捆绑资源
虽然 deno compile
目前尚不支持直接捆绑资源(尚未!),但可以将 .png
或其他资源文件转换为 base64 编码的 .js
文件,并将 它们导入到你的项目中,从而将它们包含在最终的二进制文件中。 这种方法虽然是一种变通方法,但使开发人员能够将游戏和其他资源打包在单个可执行文件中。
未来展望
我们正在根据你的反馈不断改进 deno compile
,未来的更新将简化资源捆绑、支持更多框架(如 Svelte)、减小二进制文件大小,并通过缓存进一步缩短启动时间。
🚨️ 想了解更多关于 Deno 的信息吗? 🚨️
查看我们全新的 Learn Deno 教程系列,你将在其中学习:
……以及更多内容,都在简短的视频中。新的教程每周二和周四发布。