如何将电子应用程序和烧瓶服务器打包到一个可执行文件中

时间:2018-07-21 12:05:50

标签: node.js electron electron-builder

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

我尝试了其他一些堆栈溢出的建议,并使用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)

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

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

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

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

1 个答案:

答案 0 :(得分:1)

打包的flask .app是可执行文件,不能作为子进程生成。您将必须使用execFile执行文件。我引荐了this,以下是我从网站引荐的摘录。


包装

有人要求包装。这很容易:应用有关如何打包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 /电子部分

由于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文件夹是否已生成。如果生成,则意味着我们处于“生产”模式,直接执行文件execFile;否则,请使用Python Shell生成脚本。