Nasıl Electron Uygulaması Yazarım

Javascript

Merhaba. Daha önceden github üzerinde bir repo oluşturdum. Bu repo, electron uygulaması ile yapılan (yapılacak olan) bir todo list uygulaması.

/images/posts/electron.svg Logo: https://github.com/electron/electron

Gereksinimler

Başlamadan önce bazı gereksinimlerin kurulu olması gerekiyor. Şu anda son KARARLI sürümün 1.6.9 olmasından yola çıkarak basit bi package.json dosyası hazırlayalım. Bu işe başlamadan önce bi kaç şeyi açıklığa kavuşturalım ve sonra buna göre json dosyamızı yazalım. NPM ile alakalı olanları buraya yazmıyorum. Sadece scriptlerin npm üzerinden yönetimi kolaylaştırdığını bilin.

Key Value
name Uygulamanızın adı.
productName Uygulamanızın ürün adı. Aslında Buraya açıklama yazmasanız da olur.
version Uygulamanız şu anda hangi sürümde?
main Electron uygulamasının entry pointi. Kodların bu dosya olması beklenir.

Bunlar haricinde devDependencies için electron ~ 1.6.9 olsa iyi olur. Genel itibariyle package.json dosyamıza bakarsak şöyle oluyor:

{
  "name": "uygulamaniz",
  "productName": "Basit Uygulama",
  "version": "0.1.0",
  "main": "home.js",
  "scripts": {
    "start": "electron .",
    "dev": "electron . --debug",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "electron",
    "simple",
    "app"
  ],
  "author": "Adınız Soyadınız",
  "license": "Lisans türü",
  "description": "Basit uygulamamızın basit açıklaması",
  "devDependencies": {
    "electron": "~1.6.9"
  }
}

Paket bilgilerini yazdıktan sonra aşağıdaki komutları verelim. Bu komut bağımlılıkları yükleyip, electron uygulamamızı başlatacaktır.

$ npm install && npm start

Bu arada henüz herhangi bir home.js dosyası yazmadık. Dolayısıyla da electron’a dair bir uygulama da elimizde bulunmamakta. O zaman uygulamamızın entry pointini yazalım.

Kodlama Evresi

Öncelikle direkt olarak katı kurala sahip proje yapısı yok. Bir web sitesi kodluyormuş gibi electron uygulaması yazabilirsiniz. Örneğin;

proje dizini
|
---- index.html
|
---- home.js
|
---- assets/
|
----
    \
    |
    ---- uygulamam.js
    |
    ---- uygulamam.css

Basit bir tree böyle olsun işte. Bu tamamen sizin hayal gücünüze bağlı. Ben angular ve Vue.JS kullandığımı da söyleyebilirim. Sanırım kafanızda az uz fikirler oluştu.

/images/posts/homer.png

Entry Point Yazalım

Lafı gevelemeden home.js dosyasını oluşturalım. OLuşturduğumuz bu dosyaya öncelikle gerekli kütüphaneleri dahil edelim. NodeJS biliyorsunuzdur zaten.

const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')

let win

Bu let win ne ola?

/images/posts/shocked.jpg

Yukarıdaki çocuk gibi bir şaşkınlığınız olmayacaktır muhtemelen, yazıda görsel olsun diye koydum onu. Bu let win olayı tamamen garbage collectionla alakalı. Bunu yaparak global bi referansını elimizde tutuyoruz. Hafıza kalıyor yani. Aksi durumda az önce de değindiğin garbage collectiondan dolayı pencere kapanacaktır. Ve bu açıkcası hızlı oluyor.

Şimdi asıl önemli nokta pencerenin nasıl yaratılacağıdır. Bunun için basit bir JavaScript fonksiyonu yazmanız yeterli. Ama bu koda değinelim. Öncelikle kodumuza bir bakalım:

function pencereYarat () {
  // Yeni bir pencere yarat
  win = new BrowserWindow({
    width: 800, 
    height: 600
  })

  // uygulamaya index.html dosyasını yükle (index olması şart değil)
  win.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Geliştirici araçları otomatik açık gelir
  win.webContents.openDevTools();

  win.on('closed', () => {
    /*
    Pencerenin referansını kaldırıyoruz.
    Uygulama birden fazla pencereye sahipse, 
    pencereleri bir dizide saklamanız öneriliyor.
    İlgili nesnenin (örnekte win) silineceği zaman budur.
    */
    win = null
  })
}

Yukarıdaki pencereYarat fonksiyonu, electron ile gelen BrowserWindow nesnesini kullanacağımız, entry pointin hangi dosyayı çağıracağını belirteceğimiz ve bazı spesifik ayarları belirtebileceğimiz bir fonksiyon.

Bu fonksiyonun içerisinde global tanımlı win nesnemiz de yer almakta. Burada ayrıca bildiğimiz eventlar da yer almakta. Aslında biz şu an için sadece closed eventini görüyor olsak bile kullanabileceğinizi bilin.

Yeni bir nesne yaratmak için aşağıdaki kodu kullanacağımızı zaten belirttik.

win = new BrowserWindow({
    width: 800, 
    height: 600
})

Bu kod BrowserWindow nesnesinin yükseklik ve genişliğine ait varsayılan değerleri temsil etmektedir. Kısacası uygulama 800×600 boyutlarında açılacaktır. Dilerseniz bunu değiştirebilirsiniz. Ayrıca win.setFullScreen(BOOLEAN DEĞER) kullanılarak full screen olup olmadığını ayarlayabilirsiniz.

Bilseniz iyi olur

BrowserWindow

Key Value
win.setFullScreen(true) Uygulamayı full ekran yapar, buna toolbar vs. dahil
win.maximize() Uygulamayı maksimum boyutta başlatır. Tam ekran yapmaz

Bir diğer önemli kısım ise loadURL fonksiyonu. Standart olarak gelen örneğimizde kod şu şekildedir:

  win.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

Burada yer alan protocol sizin için adeta hayat kurtarır nitelikte. Olay zaten bir browser olduğundan bu kısma yabancılık duymayacaksanız.

Eğer protocol standart olarak file: şeklinde ise, local olarak bu projenin kendi dizininde ya da herhangi bir yerde yer alan bir dosyayı çağırırsınız. Bu local dosya çağırma yöntemidir. Ayrıca slashes değeri true olursa sizin yerinize protokol slashlarını koyar.

Basit Bir Web Tarayıcısı

Dilerseniz herhangi bir web sitesini de çağırabilirsiniz. Bu durumda pathname ve protocol değerlerinde değişiklik yapmamız gerekiyor:

win.loadURL(url.format({
    pathname: 'www.google.com.tr',
    protocol: 'https:',
    slashes: true
  }))

Upps kendi tarayıcımızı yaptık. Neden olmasın ki. Hiç denemedim ama muhtemelen webkit tabanlı olduğundan iş görür gibi.

Projemiz şu an hala çalışabilir vaziyette değil ancak ilk paylaşılan kod parçacığına bakarsak win.webContents.openDevTools(); gibi bir kodu gördük. Geliştirici araçlarını otomatik olarak getirir. Buraya dair çok fazla bilgi vermeye gerek yok. Zaten yukarıda yer alan açıklama satırlar bu işleri yapıyor.

Uygulamadan Çıkış

Uygulama hazır durumda olduğunda pencereyi yani daha doğrusu pencereYarat fonksiyonunu şöyle çağıralım:

app.on('ready', pencereYarat)

Uygulamaya gerçek bi exit işlemi gerçekleştirmek için tarayıcılarda da işe yarayan CTRL / CMD + Q ya da CTRL / CMD + W kombinasyonlarını handle edip, tüm pencereleri kapatmamız gerekiyor. macOS için uyarıları varmış. Eğer kullanıcı açıkca CMD + Q yapmazsa uygulamalar ve menü çubukları aktif kalırmış. Kullanmadığım için bilgim yok.

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

Son bir adım. Yine macOS’tan bahsediliyor. Eğer ki başka herhangi bir açık pencere yok ise yani global win nesnemiz null durumda ise activate eventini kullanmak yaygın bir yöntemmiş.

app.on('activate', () => {
  if (win === null) {
    pencereYarat()
  }
})

İlk index.html Dosyası

Eğer local olarak dosya çağırıyorsanız HTML dosyanızı aşağıdaki yazabilirsiniz. Burada NodeJS’e has fonksiyonelliğin tadını çıkarabilirsiniz.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Merhaba Dünya!</title>
  </head>
  <body>
    <h1>Merhaba Dünya!</h1>
    Node.js Kullanıyoruz: <script>document.write(process.versions.node)</script>,
    Chromium Sürümü: <script>document.write(process.versions.chrome)</script>,
    Electron Sürümü: <script>document.write(process.versions.electron)</script>.
  </body>

  <script>
    // evet require ile başka dosyaları HTML içinde import edebiliriz.
    require('./baskaDosya.js')
  </script>
</html>

Uygulamayı Çalıştıralım

İlk aşamada da bahsettiğimiz şeyleri orayı atladıysanız burada tekrar yapabiliriz.

$ npm install && npm start

Tüm hepsi bu kadar. Okuduğunuz için teşekkür ederim. Yanlışlarım var ise aşağıdan bildirirseniz sevinirim.