Erstellen einer Electron-Anwendung mit der Create-React-App

Keine Webpack-Konfiguration oder "Auswerfen" erforderlich.

Ich habe kürzlich eine Electron-App mit der Create-React-App erstellt . Ich musste mich auch nicht mit Webpack herumschlagen oder meine App „auswerfen“. Ich werde Ihnen zeigen, wie ich das erreicht habe.

Ich war von der Idee begeistert, die App "create-react-app" zu verwenden, da sie die Details der Webpack-Konfiguration verbirgt. Aber meine Suche nach vorhandenen Anleitungen für die gemeinsame Verwendung von Electron und Create-React-App brachte keine Früchte, also tauchte ich einfach ein und fand es selbst heraus.

Wenn Sie sich ungeduldig fühlen, können Sie direkt in meinen Code eintauchen. Hier ist das GitHub-Repo für meine App.

Bevor wir anfangen, möchte ich Ihnen etwas über Electron and React erzählen und warum die Create-React-App ein so großartiges Tool ist.

Elektron und reagieren

React ist das JavaScript-Ansichtsframework von Facebook.

Eine JavaScript-Bibliothek zum Erstellen von Benutzeroberflächen - Reagieren

Eine JavaScript-Bibliothek zum Erstellen von Benutzeroberflächenfacebook.github.io

Und Electron ist GitHubs Framework zum Erstellen plattformübergreifender Desktop-Apps in JavaScript.

Elektron

Erstellen Sie plattformübergreifende Desktop-Apps mit JavaScript, HTML und CSS. elektron.atom.io

Die meisten verwenden Webpack für die Konfiguration, die für die React-Entwicklung erforderlich ist. Webpack ist ein Konfigurations- und Build-Tool, das der Großteil der React-Community gegenüber Alternativen wie Gulp und Grunt übernommen hat.

Der Konfigurationsaufwand variiert (dazu später mehr), und es sind viele Boilerplate- und Anwendungsgeneratoren verfügbar. Im Juli 2016 veröffentlichte Facebook Incubator jedoch ein Tool:create-react-app . Es verbirgt den größten Teil der Konfiguration und ermöglicht es dem Entwickler, einfache Befehle zu verwenden, z. B. npm startund npm run build, um seine Apps auszuführen und zu erstellen.

Was wird ausgeworfen und warum möchten Sie dies vermeiden?

create-react-app macht bestimmte Annahmen über ein typisches React-Setup. Wenn diese Annahmen nicht für Sie sind, gibt es eine Option zum Auswerfen einer Anwendung ( npm run eject). Durch das Auswerfen einer Anwendung wird die gesamte gekapselte Konfiguration von create-react-app in Ihr Projekt kopiert und eine Boilerplate-Konfiguration bereitgestellt, die Sie nach Belieben ändern können.

Aber dies ist eine einfache Fahrt. Sie können das Auswerfen nicht rückgängig machen und zurückgehen. Es gab 49 Releases (Stand dieses Beitrags) der Create-React-App, die jeweils Verbesserungen vornahmen. Bei einer ausgeworfenen Anwendung müssten Sie jedoch entweder auf diese Verbesserungen verzichten oder herausfinden, wie sie angewendet werden.

Eine ausgeworfene Konfiguration besteht aus mehr als 550 Zeilen, die 7 Dateien umfassen (Stand dieses Beitrags). Ich verstehe nicht alles (naja, eigentlich das meiste) und ich will nicht.

Tore

Meine Ziele sind einfach:

  • Vermeiden Sie das Auswerfen der React-App
  • Minimieren Sie den Klebstoff, damit React und Electron zusammenarbeiten
  • Behalten Sie die Standardeinstellungen, Annahmen und Konventionen von Electron bei und erstellen Sie eine React-App / React. (Dies kann die Verwendung anderer Tools erleichtern, die solche Konventionen annehmen / erfordern.)

Grundrezept

  1. Ausführen create-react-app, um eine grundlegende React-Anwendung zu generieren
  2. Lauf npm install --save-dev electron
  3. hinzufügen main.jsvon electron-quick-start(wir werden es der electron-starter.jsKlarheit halber in umbenennen )
  4. Ändern Sie den Aufruf von mainWindow.loadURL(in electron-starter.js), um ihn zu verwenden localhost:3000(webpack-dev-server).
  5. Fügen Sie einen Haupteintrag package.jsonfür hinzuelectron-starter.js
  6. Fügen Sie ein Laufziel hinzu, zu dem Electron gestartet werden soll package.json
  7. npm start gefolgt von npm run electron

Die Schritte 1 und 2 sind ziemlich einfach. Hier ist der Code für die Schritte 3 und 4:

const electron = require('electron'); // Module to control application life. const app = electron.app; // Module to create native browser window. const BrowserWindow = electron.BrowserWindow; const path = require('path'); const url = require('url'); // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let mainWindow; function createWindow() { // Create the browser window. mainWindow = new BrowserWindow({width: 800, height: 600}); // and load the index.html of the app. mainWindow.loadURL('//localhost:3000'); // Open the DevTools. mainWindow.webContents.openDevTools(); // Emitted when the window is closed. mainWindow.on('closed', function () { // Dereference the window object, usually you would store windows // in an array if your app supports multi windows, this is the time // when you should delete the corresponding element. mainWindow = null }) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', createWindow); // Quit when all windows are closed. app.on('window-all-closed', function () { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { app.quit() } }); app.on('activate', function () { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (mainWindow === null) { createWindow() } }); // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and require them here.

(Kern)

Und für die Schritte 5 und 6:

{ "name": "electron-with-create-react-app", "version": "0.1.0", "private": true, "devDependencies": { "electron": "^1.4.14", "react-scripts": "0.8.5" }, "dependencies": { "react": "^15.4.2", "react-dom": "^15.4.2" }, "main": "src/electron-starter.js", "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "electron": "electron ." } }

(Kern)

Wenn Sie die npm-Befehle in Schritt 7 ausführen, sollten Sie Folgendes sehen:

Sie können Live-Änderungen am React-Code vornehmen und diese sollten in der laufenden Electron-App angezeigt werden.

Dies funktioniert für die Entwicklung in Ordnung, weist jedoch zwei Mängel auf:

  • Produktion wird nicht verwendet webpack-dev-server. Es muss die statische Datei aus dem Erstellen des React-Projekts verwenden
  • (kleines) Ärgernis, beide npm-Befehle auszuführen

Angeben der loadURL in Production und Dev

In der Entwicklung kann eine Umgebungsvariable die URL für mainWindow.loadURL(in electron-starter.js) angeben . Wenn die env var existiert, werden wir sie verwenden. Andernfalls verwenden wir die statische HTML-Produktionsdatei.

Wir werden ein npm-Laufziel (zu package.json) wie folgt hinzufügen :

"electron-dev": "ELECTRON_START_URL=//localhost:3000 electron ."

Update: Windows-Benutzer müssen Folgendes tun: (Dank an @bfarmilo)

”electron-dev”: "set ELECTRON_START_URL=//localhost:3000 && electron .”

In electron-starter.jsändern wir den mainWindow.loadURLAnruf wie folgt:

const startUrl = process.env.ELECTRON_START_URL || url.format({ pathname: path.join(__dirname, '/../build/index.html'), protocol: 'file:', slashes: true }); mainWindow.loadURL(startUrl);

(Kern)

Hierbei gibt es ein Problem: create-react-app(standardmäßig) erstellt ein index.html, das absolute Pfade verwendet. Dies schlägt fehl, wenn es in Electron geladen wird. Zum Glück gibt es eine Konfigurationsoption, um dies zu ändern: Legen Sie eine homepageEigenschaft in fest package.json. (Facebook-Dokumentation auf dem Grundstück ist hier.)

Wir können diese Eigenschaft also auf das aktuelle Verzeichnis setzen und npm run buildsie als relativen Pfad verwenden.

"homepage": "./",

Verwenden von Foreman zum Verwalten von Reaktions- und Elektronenprozessen

Der Einfachheit halber ziehe ich es vor, nicht

  1. Starten / Verwalten von React Dev Server- und Electron-Prozessen (ich würde mich lieber mit einem befassen)
  2. Warten Sie, bis der React Dev-Server gestartet ist, und starten Sie dann Electron

Foremen ist ein gutes Prozessmanagement-Tool. Wir können es hinzufügen,

npm install --save-dev foreman

und fügen Sie Folgendes hinzu Procfile

react: npm startelectron: npm run electron

(Kern)

Das betrifft (1). Für (2) können wir ein einfaches Knotenskript ( electron-wait-react.js) hinzufügen , das darauf wartet, dass der React-Dev-Server gestartet wird, und dann Electron startet.

const net = require('net'); const port = process.env.PORT ? (process.env.PORT - 100) : 3000; process.env.ELECTRON_START_URL = `//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 exec = require('child_process').exec; exec('npm run electron'); } } ); tryConnection(); client.on('error', (error) => { setTimeout(tryConnection, 1000); });

(Kern)

HINWEIS: Foreman versetzt die Portnummer für Prozesse unterschiedlichen Typs um 100. (Siehe hier.) electron-wait-react.jsSubtrahiert also 100, um die Portnummer des React Dev-Servers korrekt einzustellen.

Ändern Sie nun die Procfile

react: npm startelectron: node src/electron-wait-react

(Kern)

Schließlich werden wir die Laufziele ändern package.json, um sie zu ersetzen electron-devdurch:

"dev" : "nf start"

Und jetzt können wir ausführen:

npm run dev
UPDATE (25.01.17): Ich habe den folgenden Abschnitt als Antwort auf einige Benutzerkommentare hinzugefügt (hier und hier). Sie benötigen Zugriff auf Electron aus der Reaktions-App heraus und ein einfaches Anfordern oder Importieren wirft einen Fehler auf. Ich stelle unten eine Lösung fest.

Zugriff auf Electron über die React App

Eine Electron-App besteht aus zwei Hauptprozessen: dem Electron-Host / Wrapper und Ihrer App. In einigen Fällen möchten Sie über Ihre Anwendung auf Electron zugreifen. Beispielsweise möchten Sie möglicherweise auf das lokale Dateisystem zugreifen oder Electron's verwenden ipcRenderer. Wenn Sie jedoch Folgendes tun, wird eine Fehlermeldung angezeigt

const electron = require('electron') //or import electron from 'electron';

Es gibt einige Diskussionen über diesen Fehler in verschiedenen GitHub- und Stack Overflow-Problemen, wie diesem. Die meisten Lösungen schlagen Änderungen der Webpack-Konfiguration vor, dies würde jedoch das Auswerfen der Anwendung erfordern.

Es gibt jedoch eine einfache Problemumgehung / Hack.

const electron = window.require('electron');
const electron = window.require('electron'); const fs = electron.remote.require('fs'); const ipcRenderer = electron.ipcRenderer;

Einpacken

Der Einfachheit halber finden Sie hier ein GitHub-Repo mit allen oben genannten Änderungen und Tags für jeden Schritt. Es ist jedoch nicht viel Arbeit, eine Electron-Anwendung zu booten, die die Create-React-App verwendet. (Dieser Beitrag ist viel länger als der Code und die Änderungen, die Sie benötigen würden, um die beiden zu integrieren.)

Und wenn Sie die Create-React-App verwenden, sollten Sie meinen Beitrag, Debugging-Tests in WebStorm und Create-React-App lesen.

Danke fürs Lesen. Sie können mehr meiner Beiträge auf justideas.io überprüfen

UPDATE (02.02.17). Ein Leser, Carl Vitullo, schlug vor, npm startanstelle von zu verwenden, npm run devund übermittelte eine Pull-Anfrage mit den Änderungen auf GitHub. Diese Optimierungen sind in diesem Zweig verfügbar.