pkg-node打包可执行文件工具

前言

最近在研发基于electron的桌面应用,其中涉及到外设交互部分需要使用dll实现,在经历了艰难的环境配置之后,最后由于electron内存管理问题导致应用崩溃使得electron+ffi实现动态链接库调用这条路无法走通。当时还剩下两种方案可以尝试:

  1. 自己创建dll封装原生dll调用,感觉成功几率很低。
  2. 写node addons编译成node插件,需要较强c++功底,难度较大,且最后成功概率不高。

为什么坚持了两个星期还不放弃是因为node+ffi这条路已经走通了,证明第三方的dll是没有问题的。所以试着能不能解决electron中出现的问题。

当electron不能实现的事实逐渐明朗,我开始转移方向。首先想到的是nwjs+ffi的方案,随后迅速想到为什么不使用node自己实现呢?将此部分功能单独分割成为第三方应用,通过某种通信方式实现(写缓存、数据库、http等)。最不济的情况是我为每台终端部署node服务(此应用是B2B,需要实施,不需要自己安装,这一点帮了大忙)

最好的方式是不需要安装node等一堆东西,直接是可执行文件。因此我开始寻找node打包成可执行文件的方法。

为什么要将node应用打包成可执行文件

  1. 部署方便,给客户演示和生产环境部署都很方便
  2. 保护源代码(很有用)
  3. 宿主机器其他应用对node版本可能有不同的要求
  4. 测试应用在不同node版本下兼容性

pkg打包的使用方法

将Node.js打包为可执行文件的工具有pkg、nexe、node-packer、enclose等,从打包速度、使用便捷程度、功能完整性来说,pkg是最优秀的。

安装

推荐采用局部安装

1
npm install pkg -D

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ pkg -h

pkg [options] <input>

Options:

-h, --help output usage information
-v, --version output pkg version
-t, --targets comma-separated list of targets (see examples)
-c, --config package.json or any json file with top-level config
--options bake v8 options into executable to run with them on
-o, --output output file name or template for several files
--out-path path to save output one or more executables
-d, --debug show more information during packaging process [off]
-b, --build don't download prebuilt base binaries, build them
--public speed up and disclose the sources of top-level project

Examples:

– Makes executables for Linux, macOS and Windows
$ pkg index.js
– Takes package.json from cwd and follows 'bin' entry
$ pkg .
– Makes executable for particular target machine
$ pkg -t node6-alpine-x64 index.js
– Makes executables for target machines of your choice
$ pkg -t node4-linux,node6-linux,node6-win index.js
– Bakes '--expose-gc' into executable
$ pkg --options expose-gc index.js

项目的入口点是强制CLI参数。它可能是:

  • 输入文件的路径
  • package.json ,pkg会去寻找bin属性作为入口文件
  • 路径是一个目录地址,pkg会在目录下寻找package.json文件,然后如上

targets

pkg能同时为多个平台打包。使用-t 选项,定义由三部分组成,如node6-macos-x64:

  • nodeRange node${n} or latest
  • platform freebsd, linux, alpine, macos, win
  • arch x64, x86, armv6, armv7

native addons

如果说pkg还有哪儿还可以改进的地方,那就是无法自动打包二进制模块.node文件。如果你的项目中引用了二进制模块,如sqlite3,那么你需要手动地将.node文件复制到可执行文件同一目录,我通常使用命令cp node_modules/*/.node .一键完成。但是,如果你要跨平台打包,例如在windows上打包linux版本,相应的二进制模块也要换成linux版本,通常需要你手动的下载或者编译。

后台运行与开机自启动

开机自启动原理就是将exe文件,通过命令注册到开机服务项。

SC Create 创建一个Windows系统服务
描述SC 是用于与服务控制管理器和服务进行通信的命令行程序。

命令行,有一点需要注意,等号和值之间要有空格,否则会报错

1
sc create test binPath="E:\node\app.exe" start=auto

可能遇到问题:

第一次打包的时候,会遇到下包很慢很可能超时的问题。到https://github.com/zeit/pkg-fetch/releases
下载对应的包,然后~/.pkg-cache/2.5/目录下,改名为fetched-v8.11.3-macos-x64(参考运行时下的包名字改)即可。
参考https://github.com/zeit/pkg/issues/419

windows 路径一般是用户/username/.pkg-cache

注册为系统服务

当我使用 sc create xx binPath= xx start= auto创建完系统服务后,发现启动报错,大致找了一下。

exe注册成服务了!但是启动服务的时候会报[错误1053:服务没有及时响应启动或控制请求.] ,我想应该是我的exe被服务启动后没有能回复一个服务的消息,不知道要在exe里面做什么样的操作才能不报这样的错误,不是所有的程序都能添加到服务里,要是专问的程序才行,程序里要相应控件,才会有返回值,返回告诉操作系统服务开启情况,QQ程序开发时就不是用来为作为服而设计的,所以不能当服务用

因此参考issues137找到一个nssm的工具,用法很简单。大致罗列一下

第一步:先将程序地址设置到环境变量,就把nssm.exe放到目录下好了。
第二步:nssm install servicename
第三部:按要求配置,注意设置日志输出文件和时间戳
第四步:进入服务列表进行设置,在恢复里面设置第一次失败重启(因为要做开机启动嘛),第二次也重启服务,第三次无操作,千万别设置重启电脑,之前试了一次把硬盘引导分区都破坏了,导致连BIOS都进不去,只好拆下硬盘,用其他电脑PE重做分区,还好是一个新的测试电脑。

参考

Author: sumshare
Link: http://blog.sumshare.cn/2019/05/30/pkg-node/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.