Angular on Electron
初めまして、私が@jialipassionです、初めてQiitaで投稿して、宜しくお願いします。
今までhttps://github.com/angular/zone.js でいろいろContributeしていますが、今日はElectronでAngularの開発でいくつヒントを共用します。
- Angular on Electron
- Electron Native API (NgZoneを利用する)
- 新しいzone-patch-electronの使い方(自動Patch)
Angular on Electron
ElectronでAngularの開発は普通のElectronの開発とあまり差がありません。
https://github.com/maximegris/angular-electron をベースに直接やってもいいですが、自分で@angular/cliでやっても問題ありません。
1. 環境構築
npm install @angular/cli
ng new electron-angular
cd electron-angular
npm install --save-dev electron electron-reload
そして、Electronのエントリのmain.ts
を用意します。
import { app, BrowserWindow, screen } from 'electron';
import * as path from 'path';
let win, serve;
const args = process.argv.slice(1);
serve = args.some(val => val === '--serve');
if (serve) {
require('electron-reload')(__dirname, {
});
}
function createWindow() {
const electronScreen = screen;
const size = electronScreen.getPrimaryDisplay().workAreaSize;
// Create the browser window.
win = new BrowserWindow({
x: 0,
y: 0,
width: size.width,
height: size.height
});
// and load the index.html of the app.
win.loadURL('file://' + __dirname + '/index.html');
// Open the DevTools.
if (serve) {
win.webContents.openDevTools();
}
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store window
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
}
try {
// 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 (win === null) {
createWindow();
}
});
} catch (e) {
// Catch Error
// throw e;
}
これが普通のElectronのエントリとあまり変わりません。
2. zone-mix
適用
Angularでzone.js
を利用して、ChangeDetectionを探知しています。@angular/cliでのsrc/polyfill.ts
で下記のコードがあります。
import 'zone.js/dist/zone'; // Included with Angular CLI.
これがBrowser
用のzone.js
をロードしました。でもElectronでBrowserとNodeJs両方のAPIがあって、Browserだけであれば、NodeJSのfs
とかEventEmitter
などでzone
に対応されていません。たとえば、AngularのComponentで
fs.readFile(..., (err, data) => {
// not in ngZone
// will not auto update DOM
this.content = data;
})
のようなコードで、自動てきにAngularのChangeDetectionを実行しません。
なので、Electronの場合、上記のBrowser zoneをBrowser+NodeJSのzoneを切り替える必要があります。
src/polyfill.ts
で下記のように切り替えます。
//import 'zone.js/dist/zone'; // Included with Angular CLI.
import 'zone.js/dist/zone-mix'; // Included with Angular CLI.
Electron Native API
上記の対応で、NodeJSの基本のAPIが対応されました、でもElectronのAPIがまだ対応されていません。
たとえば、ElectronのMenuItemとか、DesktopCapturerとか、これらの非同期処理するとき、CallbackがNgZoneではないので、DOMが更新していません。たとえば、AngularのComponentで下記のMenuを初期化したら、
app.component.ts
const template = [{
label: 'Edit',
submenu: [
{
label: 'submenu',
click: () => {
// not in ngZone
// title will not be updated in DOM
this.title = 'menuclicked';
}
},
]
}];
const menu = this.electron.remote.Menu.buildFromTemplate(template);
this.electron.remote.Menu.setApplicationMenu(menu);
TitleがDOMに更新されていません。
このとき、ngZone.run
が必要です。
app.component.ts
constructor(private ngZone: NgZone) {...}
ngOnInit() {
const template = [{
label: 'Edit',
submenu: [
{
label: 'submenu',
click: () => {
this.ngZone.run(() => {
this.title = 'menuclicked';
});
}
},
]
}];
const menu = this.electron.remote.Menu.buildFromTemplate(template);
this.electron.remote.Menu.setApplicationMenu(menu);
}
新しいzone-patch-electron
上記のNgZoneでElectron Native APIを対応できますが、NgZoneを意識してちょっと面倒かもしれませんが、
zone.js
で今新しいzone-patch-electron
を提供しました、(まだリリースしていないですが。。。)
https://github.com/angular/zone.js/pull/983
これがリリースしたら、ngZone.run
がいらなくなります。
使い方が、src/polyfill.ts
で
import 'zone.js/dist/zone'; // Included with Angular CLI.
import 'zone.js/dist/zone-patch-electron'; // Add this line.
を追加したら、自動的に大部のElectron APIを自動てきにPatchされます。ちょっとまだリリースしていないですが、
次のバージョンをおまちください。
以上!
どうもありがとうございました!