Без лишнего шаблона

Если вы новичок в Electron и предпочитаете ReactJS, возможно, вы наткнулись на этот шаблон на GitHub.

Этот шаблон великолепен. Однако в нем слишком много наворотов, в которых я не нуждался. Если вы похожи на меня, я просто хочу оставить свой проект React в Electron и посмотреть, как он работает.

Вот ключевые моменты, если вы хотите этого добиться.

Объединить Electron с приложением Create React или нет?

Если вы решите объединить Electron в CRA, ваш проект будет выглядеть как обычное приложение React, гдеelectron-starter.js - это точка входа для электрона.

├── Procfile
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── electron-starter.js
    ├── electron-wait-react.js
    ├── index.css
    ├── index.js
    └── logo.svg

Если это то, что вы ищете, вот подробное руководство о том, как это сделать: Создание приложения Electron с помощью create-react-app »Кристиана Сепульведы.

Но если вы переносите приложение NodeJS на Electron и хотите, чтобы серверная часть (которая теперь является основным кодом процесса) была разделена, вы можете попробовать эту структуру.

├── Procfile
├── app
│   ├── config
│   ├── events
│   ├── libs
│   ├── models
│   └── views
│       ├── js
│       │   └── preload.js
│       └── react
│           ├── README.md
│           ├── build
│           ├── package.json
│           ├── public
│           └── src
├── assets
│   └── icon.png
├── electron-wait-react.js
├── main.js
└── package.json

В этом случае main.js будет точкой входа, и папка сборки Electron не будет конфликтовать с папкой сборки CRA.

Настройка среды разработки и продукта

Поскольку вы не хотите перезапускать приложение Electron каждый раз, когда вносите изменения, вы можете указать, чтобы Electron использовал URL-адрес webpack-dev-server React.

const { app, BrowserWindow } = require('electron');
const path = require('path');
const url = require('url');
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
  width: 1024,
  height: 728
});
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, 'app/views/react/build/index.html'),
protocol: 'file:',
slashes: true
});
mainWindow.loadURL(startUrl);

Если в качестве переменной среды используется ELECTRON_START_URL, он будет использовать этот URL вместо встроенной версии React.

Благодаря упомянутому выше руководству Кристиана вы также можете использовать Foreman для управления и регистрации как Electron, так и React.

Вот здесь и пригодится Procfile. В свой Procfile добавьте скрипт npm, который запускает приложение React и приложение Electron:

react: npm run react-start
electron: npm run electron-start

И большая часть волшебства происходит в package.json.

{
"main": "main.js",
"scripts": {
"start": "nf start -p 3000",
"electron-start": "node electron-wait-react",
"react-start": "cd ./app/views/react && react-scripts start"
},
"devDependencies": {
"electron": "^6.0.9",
"electron-builder": "^21.2.0",
"foreman": "^3.0.1"
},
"directories": {
"buildResources": "assets",
"output": "release"
}
}

Когда вы запускаете npm start, он выполняет обе команды в Procfile на порту 3000.

И вы можете задаться вопросом, что делает electron-wait-react.js?

Как и в версии Кристиана, я внес небольшую поправку в журнал сообщений из приложения Electron.

Он ждет, пока запустится webpack-dev-сервер React, прежде чем запускать приложение Electron.

const net = require('net');
const port = process.env.PORT ? (process.env.PORT - 100) : 3000;
process.env.ELECTRON_START_URL = `http://localhost:${port}`;
const client = new net.Socket();
let startedElectron = false;
const tryConnection = () => client.connect({port: port}, () => {
 client.end();
 if(!startedElectron) {
  console.log('starting electron');
  startedElectron = true;
 const { spawn } = require('child_process');
 const ls = spawn('npm run electron', [], { shell: true });
 ls.stdout.on('data', (data) => {
  console.log(`${data}`);
 });
 ls.stderr.on('data', (data) => {
  console.error(`err: ${data}`);
 });
 ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
 });
}});
tryConnection();
client.on('error', (error) => {
 setTimeout(tryConnection, 1000);
});

Установить домашнюю страницу в React package.json

Если вы создаете приложение и видите пустую страницу, это связано с тем, что React не может найти свои файлы js и CSS. В вашем package.json приложении React не забудьте добавить:

"homepage": "./"

Используйте nodeIntegration

Наконец, у вас есть React, работающий в Electron, но что, если вы хотите использовать модули Electron внутри React?

После создания окна вы можете добавить nodeIntegration в webPreferences.

mainWindow = new BrowserWindow({
  width: 1024,
  height: 728,
  webPreferences: {
   nodeIntegration: true,
   preload: path.join(__dirname, 'app/views/js/preload.js')
  }
});

И в вашем приложении React вы можете потребовать это как таковое:

const { ipcRenderer } = window.require("electron");

Другая потенциальная проблема

Приложение React запрещает доступ к файлам за пределами src. Большинство решений, которые я нашел в Интернете, включают извлечение приложения React и отключение этого правила в webpack.

Но в нашем случае нам нужны были только изображения для отображения в React, поэтому мы сохранили изображение в формате base64, чтобы обойти эту проблему.

Заключение

Спасибо тем, кто создал учебники и сообщения об Electron. Ваш вклад сделал изучение Electron менее пугающим.