Как упаковать электронное приложение и флеш-сервер в один исполняемый файл

До сих пор (на моем Mac) мне удалось упаковать мое приложение фляги в один файл.app, используя pyInstaller, и я могу успешно упаковать электрон в один файл.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();
  }
});

Однако, если бы это сработало, я не понимаю, как я мог бы объединить флеш-сервер вместе с электронным приложением в один исполняемый файл?

Я был бы признателен за помощь от кого-то, кто успешно сделал это.

0 ответов

Упакованная фляга.app является исполняемым файлом и не может быть порождена как дочерний процесс. Вам нужно будет выполнить файл, используя execFile. Я сослался на это Ниже приведен фрагмент, который я сослался с сайта.


упаковка

Некоторые люди просят упаковку. Это легко: применить знания о том, как упаковывать приложения Python и приложения Electron.

Часть Python

Использование PyInstaller.

Запустите следующее в терминале:

pyinstaller pycalc/api.py --distpath pycalcdist

rm -rf build/
rm -rf api.spec

Если все идет хорошо, должна появиться папка pycalcdist / api /, а также исполняемый файл внутри этой папки. Это полный независимый исполняемый файл Python, который можно переместить куда-нибудь еще.

Внимание: должен быть создан независимый исполняемый файл Python! Поскольку целевая машина, на которую мы хотим распространять, может не иметь правильной оболочки Python и / или необходимых библиотек 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.

Другие вопросы по тегам