如何将 FIBJS 脚本打包成 exe 可执行文件

本文将会介绍如何将 FIBJS 脚本打包成Windows 上的 exe 可执行文件。

FIBJS 简介!Start it!

FIBJS 是一个主要为 Web 后端开发而设计的应用服务器开发框架,它建立在 Google v8 JavaScript 引擎基础上,并且选择了和传统的 callback 不同的并发解决方案。fibjs 利用 fiber 在框架层隔离了异步调用带来的业务复杂性,极大降低了开发难度,并减少因为用户空间频繁异步处理带来的性能问题。FIBJS 的创始人为国内知名程序员@响马老师。

脚本实例!Write it!

我们先从写一个简单的 FIBJS 脚本开始,然后将该脚本通过打包工具打包成 EXE 可执行文件。

先来创建一个文件 index.js,脚本内容如下:

1
2
3
4
5
6
7
8
9
let coroutine = require('coroutine');

let input = console.readLine("Please input something: ");

console.log("What you just typed is: ", input);

console.notice("This program will exit in 5 secends...");

coroutine.sleep(5000);

这段脚本会将你输入的内容显示在屏幕上,并且将会于 5 秒后自动退出。

如果你使用 fibjs 直接执行上述脚本,你会得到:

1
2
3
4
$ fibjs index.js
Please input something: 1
What you just typed is: 1
This program will exit in 10 secends...

开始打包!Build it!

现在我们会将上述脚本打包成为Windows 上的 EXE 可执行文件。

首先,我们需要如下这段打包代码(wrap.js):

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
var Fs = require("fs");
var Path = require("path");
var Process = require("process");
var Zip = require('zip');
var Io = require("io");
var Json = require('json');
var Os = require("os");

var LOCALCWD = Process.cwd(); //当前工作目录
var IGNOREFILES = [".gitignore", "/.git/", ".db", ".idea", ".log", "fibjs.exe", "/build/", "fib-jsToZip.js"]; //默认忽略文件及文件夹


function isFileBelong(fileList = [], path) {
return fileList.some(function (item) {
return path.indexOf(item) !== -1;
});
}


function isFileMatchRegex(path, regex) {
return path.match(regex);
}


function buildExe(from, to, memoryStream) {
memoryStream.rewind();
if (Fs.exists(to)) {
Fs.unlink(to);
}
Fs.copy(from, to); //fibjs.exe
Fs.appendFile(to, memoryStream.readAll()); //append js
}


// 路径存在返回true 否则警告返回false
function configCorrect(project) {
let pathArray = project.FibjsPath !== undefined ? [project.Location, project.Output, project.FibjsPath] : [project.Location, project.Output];

for (let i = 0; i < pathArray.length; i++) {
let path = pathArray[i];
if (!Fs.exists(path)) {
Fs.mkdir(path);
}
}
}


/**
* Pack up projects
* @param {Object} packConfig
* @return {Array} outFullPathArray
*/
function buildPack(packConfig) {

var projects = packConfig.Projects;
var projCount = 0;
var outFullPathArray = [];
var systemExePath = Process.execPath; //fibjs 执行路径

console.notice("\n\rfib-jsToZip start ... \n\r");

projects.forEach(function (proj, index) {

// 检查配置信息
configCorrect(proj);

proj.Version = proj.Version === undefined ? new Date().getTime() : proj.Version; //版本号 无则时间戳
let fileNameNoExten = proj.Name; //文件名(无扩展名)
proj.Output = Path.fullpath(proj.Output); //输出路径(zip包所在目录)
proj.OutZipFullPath = Path.join(proj.Output, fileNameNoExten + '.zip'); //zip包完整路径
proj.FibjsPath = proj.FibjsPath === undefined ? systemExePath : proj.FibjsPath; //打包fibjs.exe路径 无则打包者系统fibjs

let ms = new Io.MemoryStream();
let zipFileInMem = Zip.open(ms, 'w');
let rootIndexData = "require('./" + fileNameNoExten + "/index');"
// let dataIndex = "require('./{0}/index')();".format(fileNameNoExten); //how to format string in fibjs
zipFileInMem.write(Buffer.from(rootIndexData), "index.js"); //create index.js in root path

//递归将文件写入zip包
(function seekDir(path) {

// 忽略数组中的文件
if (isFileBelong(proj.Ignores, path)) return;

// 忽略zip包
if (isFileMatchRegex(path, /.*\.zip/ig)) return;

if (Fs.stat(path).isDirectory()) {
Fs.readdir(path).forEach(function (fd) {
seekDir(path + Path.sep + fd);
});
}
else {
zipFileInMem.write(path, Path.join(fileNameNoExten, path.replace(proj.Location, '')));
}

})(proj.Location);

zipFileInMem.close();

let zipFile = Fs.openFile(proj.OutZipFullPath, 'w');
ms.rewind();
ms.copyTo(zipFile);
zipFile.close();

console.log(" √ " + proj.Name + " > \"" + proj.OutZipFullPath + "\"");

// create exe if IsBuild is true
if (proj.IsBuild === true) {
Os.platform() === 'win32' ? buildExe(proj.FibjsPath, Path.join(proj.Output, fileNameNoExten + ".exe"), ms) : buildExe(proj.FibjsPath, Path.join(proj.Output, fileNameNoExten), ms);
}

ms.close();
projCount++;
outFullPathArray.push(proj.OutZipFullPath);
});

console.notice("\n\r √ " + projCount + " projects packed up successfully!");

return outFullPathArray; //返回各项目zip包完整路径
}

module.exports.buildPack = buildPack;

然后编写 build.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var Wrapper = require("./wrap.js");

var packConfig = {
Projects: [
{
Name: "EXE 程序名称.exe",
Location: "源码路径",
Output: "EXE 文件生成路径",
Version: "程序版本号",
Ignores: [
".gitignore",
"/.git/",
],
IsBuild: true,
FibjsPath: "使用的 fibjs 二进制文件的路径",
}
],
};

var outFullPathArray = Wrapper.buildPack(packConfig);
console.log(outFullPathArray); //返回各项目zip包完整路径

然后我们需要下载对应 Windows 版本的 FIBJS 二进制文件(下载地址:http://fibjs.org/download/index.html),置于上述配置的 FibjsPath 目录下。

执行:

1
fibjs build.js

此时 Output 路径下将会生成对应的 EXE 文件。

运行!Run it!

我们在 Windows 下运行该 EXE 文件:


本文的版权归作者 罗远航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以进行转载、分享,但不可在未经允许的情况下用于商业用途;转载请注明出处。感谢配合!