【问题标题】:How to package an electron app and flask server into one executable如何将电子应用程序和烧瓶服务器打包成一个可执行文件
【发布时间】:2018-12-29 13:18:08
【问题描述】:

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

我已经尝试了其他一些堆栈溢出帖子的建议并使用 child_process 模块来生成烧瓶 .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)

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

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();
  }
});

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

感谢成功完成此任务的人的帮助。

【问题讨论】:

    标签: node.js electron electron-builder


    【解决方案1】:

    打包的flask .app 是一个可执行文件,它不能作为子进程生成。您必须使用 execFile 执行该文件。我提到了this 以下是我从网站上提到的sn-p。


    包装

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

    Python部分

    使用 PyInstaller。

    在终端中运行以下命令:

    pyinstaller pycalc/api.py --distpath pycalcdist
    
    rm -rf build/
    rm -rf api.spec
    

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

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

    Node.js / Electron 部分

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

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

      // part of main.js
      let script = path.join(__dirname, 'pycalc', 'api.py')
      pyProc = require('child_process').spawn('python', [script, port])
    

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

    Electron 不提供检查应用程序是否未分发的功能(至少我没有找到)。所以我在这里使用了一个变通方法:检查 Python 可执行文件是否已经生成。

    在main.js中,添加如下函数:

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

    并将函数 createPyProc 更改为:

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

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

    【讨论】:

    • 感谢您发布此信息。由于这个问题,我已经有一段时间没有从事这个项目了。我必须在周末检查一下,看看这是否有效。希望它有效,我可以接受答案。
    猜你喜欢
    • 2016-07-30
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 2019-07-05
    • 2017-08-11
    相关资源
    最近更新 更多