有时候写了一个Node.js
脚本,工作中一般需要给项目内的其他同事使用,对于一些非技术的同事,使用工具相对来讲学习成本比较高,特别是需要安装Node.js
和其相关的依赖,此时,一个打包工具的需求就出现了,那么有没有好的解决方法呢?答案是肯定的,下面就介绍一个工具pkg 用于构建Node.js
项目为可执行文件,这里的 Node.js
打包 exe 是不带 GUI
界面的命令行程序。如果你想要使用 JavaScript
开发带 GUI
界面的程序,可以考虑使用 Electron
。
工具介绍
Node.js
脚本需要有Node.js
运行环境才能运行,把 Node 项目打包为 exe 就是把 Node.js
运行环境打包到项目中。因为程序中包含了 Node.js
运行环境,所以一个没有 node_modules
模块的 console.log
单文件,打包为 exe
后,文件体积也在 30M 以上。这里使用的打包工具是 pkg,,它可以把 Node.js
项目打包为 Windows
、Linux
、Mac
的可执行程序。pkg 打包的时候需要到 Node.js 的服务器(nodejs.org)下载对应版本的 Node.js,为了能顺利打包,需要有一个稳定的国际互联网连接。
- https://github.com/vercel/pkg
- https://github.com/vercel/pkg/releases 构建版本
- https://github.com/vercel/pkg-fetch/releases 对于的缓存工具下载
注意事项
支持的 Node.js 版本如下
- v19.8.1
- v18.15.0
- v16.19.1
- v14.21.3
- v12.22.11
- v10.24.1
- v8.17.0
注意:目前版本 Node.js 20
以上就不再支持了 可以考虑 Single executable applications
安装
使用 npm 全局安装 pkg:
1 | npm install pkg -g |
安装完成后可以输入:
1 | pkg -h |
或输入:
1 | pkg -v |
比如我这边输出如下:
1 | YDC012deMac-mini~(:|✔) % pkg -v |
若能显示使用说明和版本信息就说明安装成功。
简单使用
打包环境
- Mac
Node.js
v16.20.2
如何打包
创建一个 index.js
文件,随便写几行代码:
1 | console.log('我的技术博客 https://blog.asroads.com/'); |
如果你在资源管理器里直接运行打包的 exe
文件的话,代码执行完成后命令行会直接关闭,也就是说你只能看到命令行闪一下。如果要让程序不自动关闭可以使用定时器或 readline
接收输入。
我使用的是全局安装,打包前需要先进入项目目录,输入 pkg 文件名.js
,例如:
1 | pkg index.js |
首次打包会去下载对应的文件, 若下载失败 请去下载pkg-fetch后 放到本地/Users/用户名/.pkg-cache
目录下
1 | Last login: Tue Aug 6 18:53:45 on ttys001 |
打包完成后默认会在项目目录生成三个文件,其中 win.exe
结尾的就是 Windows 的程序,其它两个是 Linux 和 Mac 的。
我们选择自己的环境,我这个是MAC环境
上面的 pkg
里的 targets
是目标平台和版本配置,targets
的配置项包含三个参数,参数之间用 -
连接,下面是用到的参数说明:
node14
:Node.js 的版本,支持 node8、10、12、14、16、latest
(最新版本)win
:操作系统平台,支持alpine
、linux
、win
、macos
、linuxstatic
、freebsd
x64
:架构,支持x64
、arm64
、armv6
、armv7
进阶使用
如果你的程序中包含第三方的 Node 模块,使用 require
引入后 pkg 也能在 node_modules
查找打包,下面是包含 Express 的项目:
1 | const express = require('express'); |
打包后运行程序,在浏览器中也能访问 HTTP 服务。
配置文件
pkg 支持很多自定义打包配置,package.json
可以作为 pkg 的配置文件,下面是一些配置说明:
入口文件和输出位置
你可以直接在 package.json
中设置 pkg 的入口文件和输出位置:
1 | { |
上面主要看 pkg
和 bin
,bin
设置的 index.js
就是 pkg 的入口文件。pkg
就是 pkg 相关的配置,outputPath
就是设置 pkg 打包完成后的存放位置。
使用了配置文件后,打包也需要使用:
1 | pkg . |
静态文件
pkg 默认只会打包 require
引入的模块,如果你的项目中还包含 HTML、CSS、图片之类的静态文件的话,pkg 是不会打包的。
下面配置 pkg 打包 public
目录里的文件:
1 | { |
assets
就是静态文件打包配置,数组里的 public/**/*
就是打包 public
目录的所有文件,静态文件可以配置多个目录。
pkg 会把所有的静态文件都打包到一个 exe 程序里,运行的时候才会释放文件,程序关闭后释放的文件也会被销毁。
目标平台配置
目标平台配置可以配置集成的 Node 版本、操作系统、架构,下面是一组简单的配置:
1 | { |
上面的 pkg
里的 targets
是目标平台和版本配置,targets
的配置项包含三个参数,参数之间用 -
连接,下面是用到的参数说明:
node14
:Node.js 的版本,支持 node8、10、12、14、16、latest
(最新版本)win
:操作系统平台,支持alpine
、linux
、win
、macos
、linuxstatic
、freebsd
x64
:架构,支持x64
、arm64
、armv6
、armv7
文件路径处理
pkg 打包的程序就像 Electron 一样,执行的时候 JS 脚本才会被释放。pkg 的 Windows 程序执行的时候会释放到 C:\snapshot\项目目录
,程序关闭后,释放的 JS 也会被销毁。
对于打包到 exe 程序里的静态文件来说,你可以使用 __dirname
当前脚本目录来查找文件,但是如果你要查找 exe 程序的所在位置就不能使用 __dirname
。
要获取当前的 exe 程序位置可以使用 process.cwd()
,要获取 exe 程序目录下的其它文件可以使用 path.join(process.cwd(), '文件名')
。
其他参数-压缩
在打包的时候加入 --compress Brotli
或 --compress GZip
选项可以减小文件体积,使用方式如下:
1 | pkg . --compress |
或者:
1 | pkg index.js --compress |
使用压缩后,程序的启动时间可能会稍微增加。