如何将电子应用程序和 Flask 服务器打包成一个可执行文件

Mat*_*ugh 4 node.js electron electron-builder

到目前为止(在我的 mac 上)我已经成功使用 pyInstaller 将我的 Flask 应用程序打包到一个 .app 文件中,并且可以成功地将 Electron 打包到一个 .app 文件中。现在我希望能够将 Flask 可执行文件和 Electron 应用程序打包成一个可执行文件。

我已经尝试了其他一些堆栈溢出帖子建议的内容,并使用 child_process 模块来生成 Flask .app,但这给了我以下错误:

Uncaught Exception:
Error: spawn ../server/dist/server.app ENOENT
    at _errnoException (util.js:1024:11)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:190:19)
    at onErrorNT (internal/child_process.js:372:16)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
Run Code Online (Sandbox Code Playgroud)

这是导致此错误的我的电子入口点代码:

const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

const isDev = require('electron-is-dev');
const path = require('path');
const childSpawn = require('child_process').spawn;

let mainWindow;

const createWindow = () => {
  childSpawn('../server/dist/server.app');

  mainWindow = new BrowserWindow({ width: 900, height: 680 });
  mainWindow.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}`);

  app.setAboutPanelOptions({
    applicationName: 'app_name',
    applicationVersion: '0.0.1',
  })

  mainWindow.on('closed', () => mainWindow = null);
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {
  app.quit(); 
});

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow();
  }
});
Run Code Online (Sandbox Code Playgroud)

但是,如果这可行,我不知道如何将 Flask 服务器与电子应用程序捆绑到一个可执行文件中?

我非常感谢成功完成此操作的人的帮助。

小智 5

打包的flask .app是可执行文件,它不能作为子进程生成。您必须使用 execFile 来执行该文件。我提到了以下是我从该网站引用的片段。

\n\n
\n\n

包装

\n\n

有些人要求包装。这很简单:应用如何打包 Python 应用程序和 Electron 应用程序的知识。

\n\n

Python部分

\n\n

使用 PyInstaller。

\n\n

在终端中运行以下命令:

\n\n
pyinstaller pycalc/api.py --distpath pycalcdist\n\nrm -rf build/\nrm -rf api.spec\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果一切顺利, pycalcdist/api/ 文件夹应该显示,以及该文件夹内的可执行文件。这是完整的独立 Python 可执行文件,可以移动到其他地方。

\n\n

注意:必须生成独立的Python可执行文件!因为我们想要分发的目标机器可能没有正确的 Python shell 和/或所需的 Python 库。仅仅复制Python源代码\xe2\x80\x99几乎是不可能的。

\n\n

Node.js / Electron 部分

\n\n

由于 Python 可执行文件的存在,这很棘手。

\n\n

在上面的示例代码中,我写了

\n\n
  // part of main.js\n  let script = path.join(__dirname, \'pycalc\', \'api.py\')\n  pyProc = require(\'child_process\').spawn(\'python\', [script, port])\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,一旦我们打包了 Python 代码,我们就不应该再生成 Python 脚本。相反,我们应该 execFile 生成的可执行文件。

\n\n

Electron 不提供检查应用程序是否处于分布式状态的函数(至少我没有找到它)。所以我在这里使用一个解决方法:检查Python可执行文件是否已经生成。

\n\n

在main.js中添加以下函数:

\n\n
// main.js\n\nconst PY_DIST_FOLDER = \'pycalcdist\'\nconst PY_FOLDER = \'pycalc\'\nconst PY_MODULE = \'api\' // without .py suffix\n\nconst guessPackaged = () => {\n  const fullPath = path.join(__dirname, PY_DIST_FOLDER)\n  return require(\'fs\').existsSync(fullPath)\n}\n\nconst getScriptPath = () => {\n  if (!guessPackaged()) {\n    return path.join(__dirname, PY_FOLDER, PY_MODULE + \'.py\')\n  }\n  if (process.platform === \'win32\') {\n    return path.join(__dirname, PY_DIST_FOLDER, PY_MODULE, PY_MODULE + \'.exe\')\n  }\n  return path.join(__dirname, PY_DIST_FOLDER, PY_MODULE, PY_MODULE)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

并将函数 createPyProc 更改为:

\n\n
// main.js\n// the improved version\nconst createPyProc = () => {\n  let script = getScriptPath()\n  let port = \'\' + selectPort()\n\n  if (guessPackaged()) {\n    pyProc = require(\'child_process\').execFile(script, [port])\n  } else {\n    pyProc = require(\'child_process\').spawn(\'python\', [script, port])\n  }\n\n  if (pyProc != null) {\n    //console.log(pyProc)\n    console.log(\'child process success on port \' + port)\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

关键是检查*dist文件夹是否已经生成。如果生成,则表示我们处于\xe2\x80\x9cProduction\xe2\x80\x9d模式,直接execFile可执行文件;否则,使用 Python shell 生成脚本。

\n