将您的 Node 应用程序捆绑为适用于 Windows、Linux 和 OsX 的单个可执行文件
运行 express 示例时出现 index.html 未包含在包错误中
很多人问我一个问题:如何将 Node 应用编译成单个可执行文件。我感到很惊讶,因为这其实很简单。
询问的理由
- 保护源代码不被更改或复制——您无法在简单的文本编辑器中打开可执行文件。
- 隐藏 API 凭证- 与保护源代码相同。
- 无需 Node 或 NPM 即可运送到系统- 无需 NPM 安装依赖项,将所有内容捆绑在一个可执行文件中。
- 规定 Node 版本- 强制使用某个版本的 Node 来保证功能支持。
- 防止商业应用程序被无效——这不再像注释掉、替换或删除许可证验证功能那么简单。
- 提升性能- 这不是一个合理的理由。打包后的可执行文件性能并没有提升,而且由于它包含完整的 Node,所以比 13kb 的 JavaScript 代码要大得多(22MB)。
- 向朋友炫耀——我们有时都会这样做。
- 广泛学习- 对事物底层工作原理感兴趣的人。我最喜欢的原因。
- 看看我能做到的证据——嗯,就是这个。
市面上有一些工具可以做类似的事情。在本文中,我将重点介绍pkg,因为它是免费的(开源的),并且根据我的经验,它是迄今为止最令人愉快的工具。
包装
PKG 是一个命令行工具,可以简化应用的构建过程。运行npm i pkg -g即可全局安装。您也可以通过编程方式使用它,但我们稍后会详细介绍。
示例 Node 应用程序“prettyprint.exe”
我们将创建一个 Node 应用,用于打开一个 .json 输入文件,添加缩进(制表符、空格),并在控制台中打印出更美观、更易读的 JSON 格式。我将详细描述整个过程,并创建一个包含这些文件的 git 仓库。
NPM 初始化/package.json
使用package.json创建新 Node 应用程序的简单方法是在空目录中运行npm init 。
{
"name": "prettyprint",
"version": "0.0.1",
"description": "Pretty print a JSON file.",
"main": "main.js",
"author": "anybody",
"license": "MIT"
}
导出函数的模块
为了绝对简单起见,我们假设main.js包含一个如下所示的函数:
/* You might want to check first if the file exists and stuff but this is an example. */
const fs = require('fs')
module.exports = function(filePath) {
let data = fs.readFileSync(filePath).toString() /* open the file as string */
let object = JSON.parse(data) /* parse the string to object */
return JSON.stringify(object, false, 3) /* use 3 spaces of indentation */
}
是的,@joelnet。我们都知道你喜欢这样写。谢谢你。
module.exports = filePath => JSON.stringify(JSON.parse(require('fs').readFileSync(filePath).toString()), false, 3)
创建一个bin.js文件。
const prettyprint = require('.') /* the current working directory so that means main.js because of package.json */
let theFile = process.argv[2] /* what the user enters as first argument */
console.log(
prettyprint(theFile)
)
是的,@joelnet。可以像这样更短:
console.log(require('.')(process.argv[2]))
一个虚拟 JSON 文件,用于测试一切是否正常
或者使用您自己的 JSON 文件。
{"user":{"name":"jochem","email":"jochemstoel@gmail.com"}}
测试您是否复制/粘贴正确
如果您运行node bin.js file.json,您将会看到以下内容:
{
"user": {
"name": "jochem",
"email": "jochemstoel@gmail.com"
}
}
向 package.json 添加一个属性
只需将值为“bin.js”的属性“bin”添加到包 json 中,如下所示:
{
"name": "prettyprint",
"version": "0.0.1",
"description": "Pretty print a JSON file.",
"main": "main.js",
"bin": "bin.js",
"author": "anybody",
"license": "MIT"
}
运行 pkg
从你的应用目录运行pkg .来构建可执行文件。
如果不指定目标平台,它将同时针对 Windows、Linux 和 OSX 三个平台进行构建。
pkg .
> pkg@4.3.4
> Targets not specified. Assuming:
node10-linux-x64, node10-macos-x64, node10-win-x64
完毕!
瞧。将创建 3 个新文件。
prettyprint-win.exe
prettyprint-linux
prettyprint-macos
要查看应用程序的运行情况,请运行prettyprint-win.exe file.json。在 Linux 上,请将二进制文件修改为 a+x使其可执行,然后运行./prettyprint-linux file.json。MacOS 系统暂不支持。
额外的
相关的东西我没法挤进任何地方。
为当前平台和版本构建的简单方法
从你的应用程序文件夹运行pkg -t host .。-t表示目标平台,host表示你的系统。.表示当前目录。
当然,你也可以运行pkg --help获取完整的参数列表。
在 package.json 中,“main”和“bin”不需要不同
尽管您通常希望将它们分开,但main和bin可以具有相同的值,并且不一定需要是两个单独的文件。
依赖项需要位于 package.json 中
如果您在创建应用程序后使用 NPM 安装,它将自动将依赖项添加到 package.json。
原生模块和资产
要在可执行文件中包括资产文件/目录和/或构建依赖于本机 Node 模块的节点应用程序,请阅读文档。
...
本教程中我们所做的一切都不是绝对必要的。你不需要包含“bin”属性的整个 package.json 文件。这只是一些常见的练习,有助于你学习。你也可以只构建一个 JavaScript 文件。
PKG API
在这个例子中,我使用 PKG API 来构建单个 JavaScript 文件,而不需要整个工作目录或 package.json
/* js2exe.js */
const { exec } = require('pkg')
exec([ process.argv[2], '--target', 'host', '--output', 'app.exe' ]).then(function() {
console.log('Done!')
}).catch(function(error) {
console.error(error)
})
是的,@joelnet。可以像这样更短:
require('pkg').exec([ process.argv[2], '--target', 'host', '--output', 'app.exe' ]).then(console.log).catch(console.error)
跑步
node js2exe.js "file.js"
制作你自己的独立编译器可执行文件
你甚至可以让它自行构建,最终生成一个可以自行构建并独立构建任何其他 JavaScript 的可执行文件。一个独立的编译器。
node js2exe.js js2exe.js
现在,您可以将输出可执行文件app.exe用作不再需要 Node 或 NPM 的独立编译器。
app.exe myfile.js