18910140161

使用 pkg 打包 ThinkJS 项目

顺晟科技

2021-06-16 10:28:28

403

在ThinkJS用户群中,开发者经常提出对源代码进行加密和保护的需求。我们知道JavaScript是一种动态语言,不像其他静态语言,可以编译成二进制包,防止源代码泄露。于是出现了pkg、nexe等工具,支持JS代码和Node打包成可执行文件,解决了环境依赖问题和大家关心的源代码保护问题。

在pkg模块的README中,列出了几个主要用途。如果你有以下要求,不妨试试。

在不公开源代码的情况下为应用程序提供商业分发

在不公开源代码的情况下为应用程序提供演示

一键打包所有平台可执行文件,无需依赖相应的平台环境

提供自解压或自安装解决方案

运行应用程序不需要安装Node.js和npm

部署只需要一个文件,不需要通过npm安装大量的依赖项

资源打包后,迁移应用程序更加方便

在指定版本的Node.js下测试应用程序,不需要安装相应的版本

如何使用

关于pkg模块的基本用法,可以看文章《把你的NodeJS程序给没有NodeJS的人运行》。使用npm install -g pkg,可以在全局安装模块后在命令行上使用pkg命令。除了在命令行上指定参数,pkg还支持package.json中的配置

{

.

bin': 'production.js ',

脚本' : {

pkg': 'pkg。- out-path=dist/'

},

pkg': {

脚本' : [.]

资产' : [.],

targets': [.]

},

.

}

复制上面的代码是一个简单的配置。Bin用于指定最终打包的条目文件,pkg.scripts和pkg.assets用于指定条目文件之外需要打包成可执行文件的内容。前者用于指定其他。js文件,而后者用于指定非。js资源。Pkg.targets用于指定要打包的平台。平台名称结构如下:node $ { version }-$ { platform }-$ { arch }。版本用来指定Node的具体版本,平台用来指定编译平台,可以是freebsd、linux、alpine、macos或win,最后用arch来指定编译平台的架构,可以是x64、x86、armv6或armv7。比如Node 10-macos-x64代表基于Node 10在macos平台上打包执行的可执行程序。脚本、资产和目标都支持多种阵列配置。

在配置了门户文件、相关脚本和资源以及要编译的平台之后,执行npm run pkg来完成编译。

如何打包ThinkJS

pkg的原理是提供一个虚拟文件系统,改变__filename,__dirname等变量。以及官方API中指向本地文件系统以指向虚拟系统的变量。通过虚拟文件系统读取压缩打包的程序源代码,提供脚本执行的环境。需要注意的是,虚拟文件系统是只读的,所以如果程序中有基于__dirname的读写方法,就需要绕开。

代码预处理

在ThinkJS项目中,有两个地方可以写入文件:

项目启动后,最终的配置文件将被写入runtime/config/${env}下。数据

在生产环境中,默认情况下,在线日志写入日志/目录

默认情况下,这些目录都基于当前的项目文件夹,因此需要根据以前的理论来规避它们。pkg的README告诉我们process.cwd()还是指向真实环境的,可以把上面目录的位置修改为process.cwd()来解决这个问题。

//pkg.js

const path=require(' path ');

const Application=require(' thinkjs ');

常量实例=新应用程序({

//您可以在启动文件中自定义运行时目录

RUNTIME _ PATH : path . join(process . CWD(),' RUNTIME '),

ROOT_PATH: __dirname,

proxy: true,

env: 'pkg ',

});

instance . run();

复制代码基于production.js我们新建一个pkg.js启动文件,在项目启动后定义RUNTIME_PATH路径,将env赋给pkg,方便在后续配置中通过think.env===' pkg '切换配置。

//src/config/adapter.js

const {Console,DateFile }=require(' think-logger 3 ');

const Isdev=think . env==' development ';

const isPkg=think.env===' pkg

exports.logger={

:型isDev?控制台' : '日期文件',

控制台: {

手柄:控制台

},

日期文件: {

handle: DateFile,

等级: '全部',

正确,

模式: '-年-月-日',

总是包含模式:为真,

filename: path.join(isPkg?process.cwd() : think。ROOT_PATH,' logs/app.log ')

}

};

复制代码在适配器配置中,我们基于思考改变了原始路径。ROOT_PATH到process.cwd()。除了日志服务,如果业务中使用了缓存、会话等服务,如果也是基于文件存储,则需要修改相应的文件存储配置。当然,这些都是ThinkJS自己的一些服务。如果项目中使用了其他服务,或者如果业务逻辑涉及文件写入,则需要修改配置。

包配置

项目的写操作被绕过后,我们可以正常配置pkg,然后打包。简单pkg模块的配置大致如下:

//package.json

{

bin': 'pkg.js ',

pkg': {

资产' : [

src/**/*,

view/**/*,

www/* */* *

],

targets': [

node10-linux-x64 ',

node10-macos-x64 ',

节点10-win-x64 '

]

}

}

在这里复制代码,我们指定pkg.js作为打包的入口文件,指定编译Linux、Mac OS、Win的可执行脚本,指定将src/、view/、www/和www/打包为资源。这是因为ThinkJS是一个动态的require项目,具体的业务逻辑是在执行过程中通过遍历文件目录以读取文件的形式加载的。对于pkg模块打包,在编译过程中不可能知道这些依赖关系,所以需要打包成启动依赖的“资源”。

配置后,执行pkg。直接在项目目录中。如果一切正常,应该可以看到当前目录下的三个可执行文件,直接执行对应平台的二进制文件启动服务。

www.thinkjs.org git :(主)npm运行pkg-build

thinkjs-official @ 1 . 2 . 0 pkg-build/Users/李哲明/workspace/thinkjs/www . thinkjs . org

pkg。/out-path=dist

pkg@4.4.0

www.thinkjs.org git :(硕士)ls -alh区

总计577096

李哲明工作人员160B 12 28 17:35。

drwxr-xr-x@ 30李哲明工作人员960B 12 28 17:34.

-rwxr-xr-x 1李哲明员工87M 12 28 17:34 thinkjs-official-Linux

-rwxr-xr-x 1李哲明员工87M 12 28 17:35 thinkjs-official-macos

-rw-r - r - 1李哲明员工82M 12 28 17:35 thinkjs-official-win.exe

www.thinkjs.org git :(硕士)

复制代码后记

项目打包后,存在无法修改配置的问题。如果有动态配置的需要,就不是很方便了。下面是解决这个问题的两个想法:

动态配置被配置成环境变量,程序通过读取环境变量覆盖默认配置。

使用ThinkJS提供的beforeStartServer()钩子,在启动前读取真实目录中的配置文件,进行配置覆盖。//pkg.js

const path=require(' path ');

think.beforeStartServer(()={

const config file=path . join(process . CWD(),' config . js ');

const config=require(config file);

think . config(config);

});

复制代码

此外,随着项目复杂性的增加,可能会在业务中引入大量第三方模块。前面只是解决了ThinkJS项目本身的动态引入问题,如果引入的第三方模块也是动态引入的,需要在pkg.assets配置中显示和指定。另外,对于C模块,pkg没有办法自动引入,还需要在pkg.assets中指定依赖资源。

//package.json

{

pkg': {

资产' : [

//以node-sqlite3模块为例

' node _ modules/SQLite 3/lib/binding/node-v64-Darwin-x64/node _ SQLite 3 . node '

]

}

}

在复制的代码中,node-v64-darwin-x64根据平台的不同可能会有不同的名称。之所以。节点模块不能引入是c模块安装时会通过node-gyp动态编译,这是平台相关的。也就是说,这个特性和pkg模块可以在一个平台上封装所有平台的二进制包的特性是冲突的。毕竟pkg模块不能在Mac平台上编译Windows平台的模块。因此,在这种情况下,除了手动导入编译后的。节点模块,还应注意导入之间的一致性。节点模块和pkg.targets指定的编译平台。

除了安装。节点模块上对应的平台模块,也可以选择下载其他同学提供的编译模块。淘宝提供了很多二进制模块的编译结果。以node-sqlite3为例。它的所有编译模块都可以从npm.taobao.org/mirrors/sql下载…你可以自己选择相应的版本和平台。

本文提到的所有打包配置都已经在ThinkJS官网项目中实现。想尝试的同学可以直接克隆官网项目,安装依赖项后执行npm run pkg-build获得dist/directory中的二进制可执行文件。

我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航