So erstellen Sie eine Electron-App mit Angular und SQLite3.

Ich habe kürzlich mit der Konvertierung einer meiner Angular-Webanwendungen in eine Desktopanwendung mit Electron experimentiert. Ich bin auf dem Weg auf einige Hürden gestoßen und habe beschlossen, meine Erfahrungen schriftlich niederzulegen, damit sie anderen helfen können. Wenn Sie ähnliche Pläne für Ihr Projekt haben, hoffe ich, dass dies von Nutzen sein kann. Den Quellcode für dieses Handbuch finden Sie hier.

Teil I: Winkel

Erstellen Sie die Boilerplate.

In diesem Handbuch erstellen wir eine neue Angular-App von Grund auf neu. Ich werde Electron-Forge verwenden, um die Boilerplate zu erstellen. Electron-Forge bietet mehrere Vorlagen zum Erstellen von Boilerplate-Code, darunter eine für Angular 2. Installieren Sie zuerst die Electron-Forge-CLI.

$ npm i -g electron-forge

Verwenden Sie nun die CLI, um das Angular App Boilerplate zu erstellen.

$ electron-forge init electron-angular-sqlite3 --template=angular2$ cd electron-angular-sqlite3

Die Forge-CLI fügt das Nötigste hinzu, das wir zum Ausführen unserer App benötigen. Fügen wir ein paar zusätzliche Verzeichnisse hinzu, um unsere Datenbankdateien aufzunehmen. Fügen Sie unter src ein Assets-Verzeichnis hinzu und legen Sie Daten- und Modellverzeichnisse darunter ab.

$ mkdir ./src/assets/data ./src/assets/model

Der Verzeichnisbaum sollte nun folgendermaßen aussehen:

.+-node_modules+-src| || +-assets| | || | +-data| | +-model| || +-app.component.ts| +-bootstrap.ts| +-index.html| +-index.ts|+-.compilerc+-.gitignore+-package-lock.json+-package.json+-tsconfig.json+-tslint.json

Schreiben Sie einen Code.

Fügen Sie als ersten Schritt eine Modelldatei hinzu, die unserem Datenbankschema entspricht. In diesem einfachen Beispiel erstellen wir eine Klasse namens Item. Jedes Element enthält eine ID und eine Namenseigenschaft. Speichern Sie die Datei in Ihrem Projekt unter src/assets/model/item.schema.ts.

Wir werden TypeORM für unsere objektrelationale Zuordnung verwenden. Installieren Sie zuerst TypeORM.

$ npm install typeorm --save

Wir werden hier dem TypeORM-Handbuch zum Erstellen eines Schemas folgen. Wenn Sie fertig sind, sollte die Datei folgendermaßen aussehen:

TypeORM verwendet Typoskript-Dekoratoren. Wir verwenden den Entity Decorator, um unsere Item-Klasse als Tabelle zu deklarieren. Der @PrimaryGeneratedColumn()Dekorateur erklärt idals unsere eindeutige Identifikation und weist die Datenbank an, diese automatisch zu generieren. Wir werden uns später um die Verknüpfung mit einer Datenbank kümmern.

Erstellen Sie den Service.

Unsere nächste wahrscheinliche Maßnahme wäre die Erstellung eines App-Dienstes, der die Kommunikation vom vorderen zum hinteren Ende übernimmt. Electron stellt die IpcRendererKlasse für genau diese Sache zur Verfügung. IpcRendererist die prozessübergreifende Kommunikationsklasse von Electron, die im Renderer-Prozess verwendet wird. Grundsätzlich möchten wir das verwenden IpcRenderer, um Nachrichten an den Hauptprozess von Electron zu senden. Diese Nachrichten geben Informationen an den Hauptprozess weiter, damit dieser die Datenbankinteraktionen verarbeiten kann.

Bei der Umsetzung IpcRendererstoßen wir auf unsere erste Hürde. Electron verlässt sich auf die window.require () -Methode, die nur innerhalb des Renderer-Prozesses von Electron verfügbar ist. Dies ist ein gut dokumentiertes Problem. Um dies zu umgehen, können wir das ngx-Electron-Paket von ThornstonHans verwenden, das alle dem Renderer-Prozess ausgesetzten Electron-APIs in einem einzigen Electron-Service zusammenfasst. Mehr dazu lesen Sie hier.

Bevor wir es verwenden können ngx-electron, müssen wir es installieren.

$ npm install ngx-electron --save

Jetzt erstellen wir einen Service für unsere IpcRendererKommunikation. Erstellen src/app.service.ts.

In app.service.tserstellen wir eine Klasse namens AppServiceund fügen den @Injectable()Dekorateur hinzu. Dies ermöglicht es uns, die in Angular integrierte Abhängigkeitsinjektion (DI) zu verwenden. In unserem Konstruktor erstellen wir eine lokale Variable _electronServicevom Typ ElectronService. Die ElectronServiceKlasse wird uns von zur Verfügung gestellt ngrx-electron. Es ermöglicht uns, die Electron- IpcRenderKlasse ohne eines der oben genannten Probleme zu verwenden.

Wir erstellen drei Funktionen: eine, die alle Elemente in der Datenbank abruft, eine zum Hinzufügen eines Elements zur Datenbank und eine zum Löschen eines Elements. Jede Funktion gibt ein Observable zurück.

Observables sind Teil der RxJs-Bibliothek und bieten eine gute Möglichkeit, unsere Datenbankinteraktionen asynchron zu behandeln. Weitere Informationen zu Observables finden Sie hier. Beachten Sie die Verwendung des Observable-Operators of, um anzuzeigen , dass wir unsere Antwort this._electronService.ipcRenderer.sendSync()als Observable-Wert umschließen.

Registrieren von Diensten und Schreiben von Komponenten.

Nachdem unser Service abgeschlossen ist, können wir src/app.component.tsihn für DI registrieren. Während wir dort sind, werden wir eine einfache HTML-Vorlage und Funktionen hinzufügen, um unsere Schaltflächenereignisse zu behandeln.

Stellen Sie sicher, dass Sie AppServiceals Provider in den @NgModuleDecorator-Argumenten und auch als private Variable im AppComponentKonstruktor hinzufügen . Wir müssen auch ElectronServiceals Anbieter hinzufügen .

Bei der Initialisierung unserer Komponente möchten wir den gesamten Inhalt unserer Datenbank laden und anzeigen. Dazu abonnieren wir die addItem()Funktion des von uns erstellten Dienstes. Wenn Sie sich erinnern, geben alle unsere Servicefunktionen Observables zurück. Um Daten von unserem Observable zu erhalten, abonnieren wir sie und übergeben eine Rückruffunktion, die ausgeführt wird, wenn die Daten empfangen werden. Im obigen Beispiel wird (items) => (this.itemList = items) unsere Klassenvariable nach dem Abrufen le itemLmit dem Inhalt der Datenbank füllen .

Wir folgen ähnlichen Taktiken zum Hinzufügen und Löschen von Elementen aus der Datenbank. Jedes Mal itemListmit dem aktualisierten Inhalt der Datenbank neu füllen.

Teil II: Elektron

SQLite3 installieren.

Nachdem wir unser Frontend fertiggestellt haben, müssen wir das Electron-Backend erstellen. Das Electron-Backend verarbeitet und verarbeitet von vorne gesendete Nachrichten und verwaltet die sqlite3-Datenbank.

Wir werden sqlite3 für unsere Datenbank verwenden und müssen es installieren.

$ npm install sqlite3 --save

Eine Hürde, auf die ich bei der Arbeit mit sqlite3 und Electron gestoßen bin, war, dass die nativen Binärdateien von sqlite für die Verwendung mit Electron neu kompiliert werden müssen. Electron-Forge sollte dies für Sie erledigen. Zu beachten ist, dass Electron-Forge Node-Gyp verwendet, um die Binärdateien zu kompilieren. Möglicherweise muss es vor der Verwendung ordnungsgemäß installiert und konfiguriert werden, einschließlich der Installation von Python. Ab sofort verwendet Node-Gyp Python 2. Wenn Sie mehrere Versionen auf Ihrem Computer haben, müssen Sie sicherstellen, dass der aktuelle Build die richtige verwendet.

Verbindung zur Datenbank herstellen.

Now let’s open our src/index.ts file and add some code to connect to the database. The two things we need to do are, connect to the database, and add functions to handle our requests from the renderer process. The finished file looks like this:

An in depth explanation of TypeORM and Electron is beyond the scope of this

guide, so I will only briefly discuss the above file. First we need to import the createConnection class from the TypeORM library. We also need to import or Item schema.

As expected, the createConnection class will create a connection to our database. We pass it a constructor with parameters such as type, database, and entities. Type is a string that describes what type of database we are using. Database is a string that points to the database location. Entities is where we tell TypeORM what schemas to expect. For our purpose: type is ‘sqlite’, Database is ‘./src/assets/data/database.sqlite’, and Entities is our imported Item class.

TypeORM allows you two options when working with database transactions: EntityManager and Repository. Both will give you access to functions for querying the database, without writing the SQL. We create a Repository object with the line itemRepo = connection.getRepository(Item) . This gives us access to transaction methods for our Item table.

The last step is to create functions to handle the messages being sent from the IpcRenderer. Each function will use the itemRepo object we created to access the database. After successful completion of each transaction, the functions will pass the new state of the database back to the renderer.

Part III: Run it!

With everything complete, we can now run the app. Electron-Forge handles this process for us. All we need to do is run the command:

$ npm run start

If everything is correct, Electron will open your app and you can test it out.

Thanks for reading!