当前位置:   article > 正文

Node项目pkg打包ES6,以及多进程child-process.fork方式_pkg es6

pkg es6

本文地址:https://superliii.blog.csdn.net/article/details/124114250 (拒绝搬运)

前言

最近项目搞得差不多了,开始尝试打包Node后台程序。
关于这个问题我卡了两天,尝试了各种办法,期间也走了不少弯路。
相关方面资料太少,在此分享出一套方案实现。
帖子有些啰嗦,你可以直接下载我的工程案例瞅一下:案例工程


问题

pkg用起来各种问题,不知道pkg是压根就不支持ES6还是我没搞明白,但它明明引用了babel
在这里插入图片描述

解决

好吧,我们自动手动搞一个babel ES6->ES5编译过程。

1.首先在项目里面装个babel和pkg

npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
npm install --save-dev pkg
  • 1
  • 2

2.然后根目录下创建个.babelrc文件

{
    "presets": [
      "@babel/preset-env"
    ]
  }
  • 1
  • 2
  • 3
  • 4
  • 5

3.修改package.json

{
   ...
   "type": "module",
   "bin": "dist/es5/index.js",
   "pkg": {
	    "options": [
	      "experimental-modules"
	    ],
	    "scripts": "dist/es5/**/*.js",
	    "targets": [
	      "node16-win-x64"
	    ],
	    "outputPath": "dist"
   },
    "scripts": {
    ...
    "build": "babel src -d dist/es5 && pkg ."
    ...
  },
  ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

解释下,上面这些参数都是干啥的:

备注
type告诉NodeJS我们的JS使用ES6的是语法。
binpkg要打包程序的入口文件
pkgpkg的一堆参数配置
pkg->optionspkg要打包程序的入口文件
pkg->scripts一些动态引用无法被pkg捕捉到,我们需要告诉pkg这些东西也要一并打包出去。比如import(‘aaa.js’)这样的语法。
pkg->targets要构建的目标平台,有许多,比如node16-linux-arm64,请自行搜索
scripts->build这里是我们写的自动构建命令行,让babel完事儿后自动pkg

所以以上就实现了pkg构建es6项目。
但事情还没有结束,我们还需要对fork做处理。


重点:fork子进程处理

按照我们以往node的开发习惯,直接fork另一个路径的js就搞定了,但是在pkg中有所不同:

假设我们有index.js和child.js两个文件,经过pkg打包后你会发现干净到只有一个exe可执行文件。
所以我们直接fork(‘child.js’) pkg是找不到child.js这个文件的,除非你把他复制了过去。

那么这个child.js被打包到哪去了呢?

用notepad++打开发布后的exe文件看了下,pkg就简单粗暴的把代都合并在里面,并没有加密混淆。在这里插入图片描述
所以如果我们需要保护代码,需要在babel后用Uglifyjs混淆一下。
如果需要压缩,pkg提供了压缩指令,我们只需修改打包指令为pkg . -C Gzip
关于压缩算法pkg还提供了Brotli算法,对比戳这

话说回来

无意中发现,pgk打包后的process.argv[1]输出为C:\snapshot\…
在这里插入图片描述
这个东西就很奇怪,看了一下C盘下并没有snapshot这个目录,于是猜想它应该是个某种虚拟目录。

翻箱倒柜,作者在github上给出了关于snapshot快照部分的介绍
链接: https://github.com/vercel/pkg#snapshot-filesystem

在此,我搬来翻译一下(为便于理解,有所修改):

快照文件系统(Snapshot filesystem)


在打包过程中,收集项目文件并将其放入可执行文件中,它称为快照。
在运行时,打包的应用程序可以访问所有文件所在的快照文件系统。
.
如果你需要使用路径,则以下取值你很可能会用到。

value 值with(node)打包前packaged 打包后comments 备注
__filename/project/app.js/snapshot/project/app.js打包后为虚拟快照路径
__dirname/project/snapshot/project打包后为虚拟快照路径
process.cwd()/project/project真实的运行路径
process.execPath/usr/bin/nodejs/deploy/app-x64运行程序路径
process.argv[0]/usr/bin/nodejs/deploy/app-x64命令行参数0 (执行程序)
process.argv[1]/project/app.js/snapshot/project/app.js命令行参数1(一般是指.js文件)
process.pkg.entrypointundefined/snapshot/project/app.js入口文件路径
process.pkg.defaultEntrypointundefined/snapshot/project/app.js默认入口文件路径
require.main.filename/project/app.js/snapshot/project/app.js入口文件路径

注意:在 Windows 中,路径会具有盘符前缀。

因此,为了使用在打包时收集的文件(js文件或任何资产),您应该采用 __dirname、 或 __filename作为路径计算的基础。对于javascript文件,您可以只是或因为它们默认使用当前。对于资产,请使用 .有关详细信息,请参阅检测源代码中的资产。
.
另一方面,为了在运行时访问真实的文件系统,你应该使用process.cwd()或path.dirname(process.execPath)。

在windows上实测效果如下:

value 值with(node)打包前
__filenameC:\snapshot\test\dist\es5\index.js
__dirnameC:\snapshot\test\dist\es5
process.cwd()F:\****\test\dist
process.execPathF:\****\test\dist\test.exe
process.argv[0]F:\****\test\dist\test.exe
process.argv[1]C:\snapshot\test\dist\es5\index.js
process.pkg.entrypointC:\snapshot\test\dist\es5\index.js
process.pkg.defaultEntrypointC:\snapshot\test\dist\es5\index.js
require.main.filenameC:\snapshot\test\dist\es5\index.js

所以,我们应该在fork里,使用绝对路径来替代相对路径。

cprocess.fork(__dirname + "/child.js", {
    env: { a: "aaa" },
});
  • 1
  • 2
  • 3

这样发布后欠确实是好用了

但是!!

在ES6中,Node没有提供__dirname、__filename。
在这里插入图片描述
所以现在的情况是:直接node运行会报__dirname undefind错误。

查了下node文档,上面告诉我们可以使用import.meta.url替代。
但是它无法被babel转为es5。pkg后依旧会报错,且这个错误try捕捉不到。大崩直接退进程!
JS不像C++有宏编译,不能根据运行环境编译不同代码。

所以

要么我们在外部配置文件指定__dirname,要么我们干脆就抛弃它。

于是…
你也许会考虑fork自身入口文件,通过不同的命令行参数来执行不同的任务,就像Chrome那样。
事实上你是对的,这样确实行得通。我们来尝试一下:

创建一个src目录,随后在搞两个测试文件index.js和child.js

//index.js
import cprocess from "child_process";
import child from "./child.js";
if (process.env.a == null) {
    console.log("LOL!!", process.argv0, process.argv[1]);
    cprocess.fork(process.argv[1], {
        env: { a: "aaa" },
    });
} else {
    child();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
//child.js
export default function () {
    console.log("IM CHILD!!");
}
  • 1
  • 2
  • 3
  • 4

案例工程下载:https://download.csdn.net/download/cbaili/85113925

运行一下,成功了!
这套机制使用import的方式,成功的规避掉了ES6 __dirname找不到的问题。
index.js是入口文件,主要负责不同进程的fork操作。
通过不同的env参数,区分不同的fork操作。


完结撒花,这是一套实在的解决方案,拿来分享给大家。
觉得有用记得点赞收藏哦~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/481816
推荐阅读
相关标签
  

闽ICP备14008679号