Автор оригинала: FreeCodeCamp Community Member.
Уильямом Boxx.
Я недавно был экспериментирован с преобразованием одного из моих угловых веб-приложений в настольное приложение с использованием электрона. Я столкнулся с несколькими препятствиями по пути и решил поставить свой опыт в письменном виде, чтобы он мог помочь другим. Если у вас есть похожие планы на ваш проект, я надеюсь, что это может быть использовано. Исходный код для этого руководства можно найти здесь Отказ
Часть I: Угловой
Создайте бойную табличку.
Ради этого руководства мы будем создавать новое угловое приложение с нуля. Я буду пользоваться Электронно-кузница создать котельной. Electron-Forge предлагает несколько Шаблоны Для создания кода Boverplate, включая один для угловых 2. Сначала установите электрон-Forge CLI.
$ npm i -g electron-forge
Теперь используйте CLI для создания угловой котельной приложения.
$ electron-forge init electron-angular-sqlite3 --template=angular2 $ cd electron-angular-sqlite3
CLI CLI добавит голые необходимые основы, нам нужно запустить наше приложение. Давайте добавим несколько дополнительных каталогов для размещения наших файлов базы данных. Добавьте каталог активов под SRC и поставить данные и модели каталогов под нем.
$ mkdir ./src/assets/data ./src/assets/model
Дерево каталога теперь должно выглядеть так:
. +-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
Напишите какой-нибудь код.
В качестве нашего первого шага давайте добавим файл модели, который мы будем соответствовать нашей схеме базы данных. Для этого простого примера давайте создадим класс называемый элемент. Каждый элемент будет содержать идентификатор и свойство имени. Сохраните файл в вашем проекте в SRC/Активы/Модель/item.schema.ts Отказ
Мы будем использовать t ypeorm Для нашего объекта реляционное отображение. Первый вход в установку.
$ npm install typeorm --save
Мы будем следить за типом Руководство Для создания схемы здесь. Когда закончите файл должен выглядеть так:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Item
{
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}Внешник использует TeampScript Декораторы Отказ Мы используем декоратор Entity, чтобы объявить наш элемент класса таблицей. @PrimaryGeneratedColumn () Декоратор объявляет ID В качестве нашей уникальной идентификации и сообщает базу данных автоматически генерировать ее. Мы будем беспокоиться о связи с базой данных позже.
Создайте услугу.
Наши следующие вероятные действия будут создавать прикладную службу, которая обрабатывает связь с передней части к задней части. Электрон делает доступным IPCRENDER класс только для этой вещи. IPCRENDER это электрон Межух технологический коммуникационный класс это используется в процессе рендерера. В основном, мы хотим использовать IPCRENDER отправлять сообщения в основной процесс электрона. Эти сообщения передают информацию в основной процесс, чтобы он мог справиться с взаимодействиями базы данных.
Реализация IPCRENDER Где мы столкнулись с нашим первым препятствием. Электрон полагается на метод window.require (), который доступен внутри процесса рендерера электрона. Это хорошо документировано Выпуск Отказ Чтобы обойти это, мы можем использовать Thornstonhans ‘NGX-Electron Пакет, который оборачивает все электронные API, подвергается воздействию процесса рендерера в одну электронную службу. Вы можете прочитать больше об этом здесь Отказ
Прежде чем мы сможем использовать NGX-Electron Нам нужно установить его.
$ npm install ngx-electron --save
Теперь давайте создадим сервис для обработки наших IPCRENDER коммуникация. Создать src/app.service.ts Отказ
import { Injectable } from '@angular/core';
import { Item } from './assets/model/item.schema';
import { ElectronService } from 'ngx-electron';
import { Observable } from 'rxjs/observable';
import { of } from 'rxjs/observable/of';
import { catchError } from 'rxjs/operators';
@Injectable()
export class AppService {
constructor(private _electronService: ElectronService) {}
getItems(): Observable- {
return of(this._electronService.ipcRenderer.sendSync('get-items')).pipe(
catchError((error: any) => Observable.throw(error.json))
);
}
addItem(item: Item): Observable
- {
return of(
this._electronService.ipcRenderer.sendSync('add-item', item)
).pipe(catchError((error: any) => Observable.throw(error.json)));
}
deleteItem(item: Item): Observable
- {
return of(
this._electronService.ipcRenderer.sendSync('delete-item', item)
).pipe(catchError((error: any) => Observable.throw(error.json)));
}
}
В app.service.ts Мы создаем класс под названием Appservice и добавьте @Injectable () декоратор. Это позволяет нам использовать встроенную инъекцию имзависимостей угловых углов (DI). В нашем конструкторе мы создаем локальную переменную _Electronservice типа Электронсервис Отказ Электронсервис Класс предоставляется нам Ngrx-Electrone Отказ Это позволяет нам использовать электрон IPcrender класс без каких-либо вышеупомянутых вопросов.
Мы создаем три функции: тот, который получает все элементы в базе данных, один, чтобы добавить элемент в базу данных и один для удаления элемента. Каждая функция вернет наблюдаемый.
Наблюдаемые части являются частью Библиотека RXJS И предоставить хороший способ обработки взаимодействий в базе данных асинхронно. Вы можете узнать больше о наблюдаемых здесь Отказ Обратите внимание на использование наблюдаемого оператора Чтобы обозначить, что мы обертываем наш ответ от this._electronservice.ipcrenderer.sendsync () как наблюдаемое значение.
Регистрация услуг и компонент написания.
С нашим обслуживанием завершен, давайте пойдем в src/app.component.ts и зарегистрируйте его для ди. В то время как там мы добавим простой HTML-шаблон и функции для обработки наших событий кнопок.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, OnInit } from '@angular/core';
import { Item } from './assets/model/item.schema';
import { AppService } from './app.service';
import { ElectronService } from 'ngx-electron';
@Component({
selector: 'App',
template: `
Welcome to {{ title }}!
Here is the contents of the database:
-
{{ item.name }}
`,
})
export class AppComponent implements OnInit {
public readonly title = 'my app';
itemList: Item[];
constructor(private appservice: AppService) {}
ngOnInit(): void {
console.log('component initialized');
this.appservice.getItems().subscribe((items) => (this.itemList = items));
}
addItem(): void {
let item = new Item();
item.name = 'Item ' + this.itemList.length;
this.appservice.addItem(item).subscribe((items) => (this.itemList = items));
}
deleteItem(): void {
const item = this.itemList[this.itemList.length - 1];
this.appservice
.deleteItem(item)
.subscribe((items) => (this.itemList = items));
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ],
providers: [ AppService, ElectronService ],
})
export class AppModule {}Убедитесь, что добавить Appservice Как провайдер в @Ngmodule Декораторные аргументы, а также в качестве частной переменной в AppComponent конструктор. Нам также нужно добавить Электронсервис как провайдер.
По инициализации нашего компонента мы хотим загрузить все содержимое нашей базы данных и отображать его. Для этого мы подписываемся на AddiTem () Функция сервиса, которую мы создали. Если вы помните, все наши сервисные функции возвращают наблюдаемые. Чтобы получить данные из нашего наблюдаемого, мы подписываемся на него, передавая функцию обратного вызова, которая выполняется при получении данных. В приведенном выше примере (предметы) => MS) заполнит нашу переменную класса le iteml IST с содержимым базы данных после того, как он получен.
Мы следуем подобной тактике для добавления и удаления элементов из базы данных. Каждый раз, когда выпаривают reatlist с обновленным содержанием базы данных.
Часть II: Электрон
Установка SQLite3.
Теперь, когда мы закончили наш передний конец, нам нужно создать электронную вершину. Отверженность электронов будет обрабатывать и обработать сообщения, отправленные спереди и управлять базой данных SQLite3.
Мы будем использовать SQLite3 для нашей базы данных и необходимо установить его.
$ npm install sqlite3 --save
Прекрас, в котором я столкнулся, работая с SQLite3 и Eneral изначально, это было то, что родные двоичные двоики SQLite должны быть перекомпилированы для использования с электроном. Электронно-кузница должна заботиться об этом для вас. Одно можно отметить, Electron-Forge будет использовать Узел-GYP скомпилировать двоичные файлы. Возможно, вам придется правильно установить и настроить перед использованием, который включает в себя установку Python. Как сейчас Узел-GYP использует Python 2. Если у вас есть несколько версий на вашем компьютере, вы должны убедиться, что текущая сборка использует правильный.
Подключение к базе данных.
Теперь давайте откроем наш SRC/index.ts Файл и добавьте код для подключения к базе данных. Две вещи, которые нам нужно сделать, подключаются к базе данных и добавляют функции для обработки наших запросов от процесса рендерера. Готовый файл выглядит так:
import { app, BrowserWindow, ipcMain } from 'electron';
import { enableLiveReload } from 'electron-compile';
import { createConnection } from 'typeorm';
import { Item } from './assets/model/item.schema';
// 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: Electron.BrowserWindow | null;
const isDevMode = process.execPath.match(/[\\/]electron/);
if (isDevMode) enableLiveReload();
const createWindow = async () => {
const connection = await createConnection({
type: 'sqlite',
synchronize: true,
logging: true,
logger: 'simple-console',
database: './src/assets/data/database.sqlite',
entities: [ Item ],
});
const itemRepo = connection.getRepository(Item);
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
});
// and load the index.html of the app.
mainWindow.loadURL(`file://${__dirname}/index.html`);
// Open the DevTools.
if (isDevMode) {
mainWindow.webContents.openDevTools();
}
// Emitted when the window is closed.
mainWindow.on('closed', () => {
// 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;
});
ipcMain.on('get-items', async (event: any, ...args: any[]) => {
try {
event.returnValue = await itemRepo.find();
} catch (err) {
throw err;
}
});
ipcMain.on('add-item', async (event: any, _item: Item) => {
try {
const item = await itemRepo.create(_item);
await itemRepo.save(item);
event.returnValue = await itemRepo.find();
} catch (err) {
throw err;
}
});
ipcMain.on('delete-item', async (event: any, _item: Item) => {
try {
const item = await itemRepo.create(_item);
await itemRepo.remove(item);
event.returnValue = await itemRepo.find();
} catch (err) {
throw err;
}
});
};
// 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', () => {
// 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', () => {
// 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 import them here.Углубленное объяснение двойного и электрона выходит за рамки этого Руководство, поэтому я буду только кратко обсудить вышеуказанный файл. Сначала нам нужно импортировать CreateConnection класс из входной библиотеки. Нам также нужно импортировать или схему предмета.
Как и ожидалось, CreateConnection Класс создаст подключение к нашей базе данных. Мы передаем его конструктор с параметрами, такими как тип, база данных и объекты. Тип – это строка, которая описывает, какой тип базы данных мы используем. База данных – это строка, указывающая на местоположение базы данных. Сущности – это то, где мы даем впринимаем, какие схемы ожидать. Для нашей цели: тип «SQLite», база данных «./src/assets/data/database.sqlite», и объекты – наш импортированный класс элементов.
Tourmm позволяет вам два варианта при работе с транзакциями базы данных: Entitismanager и Репозиторий Отказ Оба дадут вам доступ к функциям для запроса базы данных, не написав SQL. Мы создаем объект репозитория с линией Itemrepo.getRepository (товар) . Это дает нам доступ к методам транзакции для нашей таблицы товара.
Последний шаг – создавать функции для обработки отправленных сообщений из IPCRENDER Отказ Каждая функция будет использовать Itemrepo Объект, который мы создали для доступа к базе данных. После успешного завершения каждой транзакции функции пройдут новое состояние базы данных обратно в рендерер.
Часть III: Беги!
Со всем завершенным, теперь мы можем запустить приложение. Электронно-кузнец обрабатывает этот процесс для нас. Все, что нам нужно сделать, это запустить команду:
$ npm run start
Если все правильно, Electron откроет ваше приложение, и вы можете проверить его.
Спасибо за прочтение!
Оригинал: “https://www.freecodecamp.org/news/creating-an-electron-app-using-angular-and-sqlite3-24ca7d892810/”