47

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

 4 years ago
source link: http://blog.luoyuanhang.com/2019/11/25/fibjs-wrapper/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

FIBJS 简介!Start it!

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

脚本实例!Write it!

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

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

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 直接执行上述脚本,你会得到:

$ 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):

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:

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 目录下。

执行:

fibjs build.js

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

运行!Run it!

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

fUzeeyB.png!web

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK