シンプルにNimでElectronをつかってみる

## サンプル
たのしくなって、基本的なところを実験してみました。

下記に、そのときのサンプルをあげました。

https://github.com/MoonSeaSkyFish/nim_electron_test

クイックスタートから、プロセス間通信、ファイルの読み込みなどのサンプルですので、これだけわかれば、一通りのことは使えるようになるのではないでしょうか。

下記は、quickstart の説明になります。

## クイックスタート

OSは、Linuxを使っています。

前提条件として、下記のツールを入れておいてください。

- nim
- npm
- node.js


話をもどします。

入っていたら、早速はじめましょう。

まず、テスト用のディレクトリをつくって、npm initしましょう。

```shell
% mkdir nim-electron-test
% cd nim-electron-test
% npm init -y
```
package.jsonがつくられたはずです。

つぎに、electronをインストールしましょう。

```shell
% npm i -D electron
```

同じディレクトリに、index.nimという名前で、下記のコードを書いて保存ください。

```nim:index.nim
import jsffi

let electron = require("electron")
let app = electron.app

app.whenReady().then(proc() = 
  (jsnew electron.BrowserWindow()).loadFile("index.html")
)

app.on("window-all-closed", proc() =
  if require("process").platform.to(cstring) != "darwin":
    app.quit()
)
```

require は、jsffi モジュールに入っている、javascriptのライブラリを読み込むもののようです。

参考：( https://nim-lang.org/docs/jsffi.html )

次に、index.htmlに、適当になにか書いてください。
ここでは面倒なのでタグなど書かず、以下のように書いたことにします。

```html:index.html
こんにちわ
```

保存したら、コマンドラインで以下を実行します。

```shell
% nim js index.nim
```
エラーが出ていなければ、index.jsというファイルができています。

できていたら、下記を実行してください。

```shell
% npx electron .
```

一番最後に、ピリオド（.）の入力を忘れないようにしてください。

問題なければ、新しいwindowが開いて、「こんにちわ」と表示したと思います。

さて次にwindowの大きさを変えてみます。
ソースコード(index.nim)の一部に、下記のコードがあります。

```nim
(jsnew electron.BrowserWindow()).loadFile("index.html")
```

ここの「jsnew electron.BrowserWindow()」の()内に、大きさの指定を書きます。
Nimなので、インデントは忘れないように。

```nim
(jsnew electron.BrowserWindow(
  JsObject{
    width: 100,
    height: 200
  }  
)).loadFile("index.html")
```

保存したら、前述したように、nim js ...して、npx ....を実行してみてください。
小さくなったwindowが開きましたか？

おまけで、preloadも記述します。
preloadがなにかは、ご自身でしらべてください。

index.nimの、大きさ指定したコードにつけたします。

```nim
(jsnew electron.BrowserWindow(
  JsObject{
    width: 100,
    height: 200,
    webPreferences: JsObject{
        preload: "preload.js"
    }
  }  
)).loadFile("index.html")
```

preload.js は、nimのコードで記述したければ、別途コンパイルが必要になります。
追記ですが、preload.jsは、フルパスで指定する必要があります。

```shell
% nim js preload.nim
```

index.htmlから外部ファイルで読み込みたいソースも、別途コンパイルが必要です。


```shell
% nim js renderer.nim
```

その場合、index.htmlには、以下のように記述が必要でしょう。

```html:index.html
<script src="renderer.js"></script>
```

以上です。

## 閑話休題

よく、nim+electronで、参考にするのは、下記のサイト？だと思います。

https://github.com/PMunch/nim-electron

これ、このままだと、electronが起動しません。
package.json内の、electronのバージョンが古すぎて、gconfなんたらがないと文句いわれて落ちます。
調べると、昔のchromeを入れてると自動でインストールされたらしいのですが、今は使わないとのこと。
なので、package.jsonの下記の部分を削除して、（もしくはバージョンを書き換えて）、最新のelectronをインストール必要があります。

```json:package.json
"devDependencies": {
    "electron": "~1.6.2"
  }
```

また、main.nimも、なぜか、app.nimで作成されたアプリとsocket通信するサンプルになっています。
なので、このままだと、落ちます。
socket通信している部分は削除が必要です。

```nim:main.nim
var client = jsnew net.createConnection(JsObject{ port: 1234 }, proc () =
  console.log("Connected to server!")
)
```

```nim:main.nim
 client.write "Hello, world\r\n"
```

上記２箇所は不要です。

また、不要なモジュールをロードする必要がないので消しましょう。

```nim:main.nim
{.emit: """
const electron = require('electron')
const path = require('path')
const url = require('url')
const net = require('net');
""".}
```

ここでいえば、一番下のnetは不要です。

これで、上記のサンプルは動作します。

さて、emitですが……（これは、コンパイル時に指定した言語を実行するものらしいです）

jsffiのドキュメントを英語がわからないなりに、ながめていると、requireというプロシージャがあるではないですか。

なので、思い切って、このemitの部分は削除して、直接、requireでelectronをロードしてみたら、うまく動作しました。

最近のelectronだと、BrowserWindowは、loadURL ではなく、loadFileを使うようです。

そうなると、urlモジュールは不要です。consoleは、デバッグする必要がなければ不要でしょうし、そもそも、ふつうにechoでもいけました。（レンダラープロセスで動作するかは不明）

__dirnameや、pathは、お好みでどうぞ、だと思います。
たぶん、こんな感じ。

```nim
let dirname {.importc: "__dirname", nodecl.}:cstring
let path = require("path")
```

dirname ですが、nim はアンダーバーではじまる変数名は使えないので、はずしてあげなきゃいけないです。最初から、cstringにしておけば、dirname.to(cstring) としなくても良いようです。

使う場合は、loadFileの引数で下記のように利用しているようです。loadFromの前は省略。

```nim
loadFile(dirname & "/index.html")
# または、
loadFile(path.resolve(dirname, "index.html"))
```

次にprocessは、一回しか使わないので、

```nim
if require("process").platform.to(cstring) != "darwin":
  app.quit()
```

としています。

macで動作することを考慮しないのであれば、このif文は不要です。
蛇足ですが、macはwindowを閉じても、終了しない仕様なので、この判定をしています。

このように、できるかぎり削除していったら、最初の、main.nim ではなくて、index.nimのようになりました。

index.nimにしたのは、単に、npm init したときにできるpackage.jsonのデフォルトがmain.jsだからです。

ところで、自分で書いたコードなのですが、冷静になると、下記のコードはやりすぎ感はあります。

```nim:index.nim
app.whenReady().then(proc() = 
  (jsnew electron.BrowserWindow()).loadFile("index.html")
)
```

proc内は、下記のように分けたほうが使い勝手はよいでしょう。

```nim:index.nim
app.whenReady().then(proc() = 
  let win = jsnew electron.BrowserWindow()
  win.loadFile("index.html")
)
```

他に下記コードは必要か不要か、好みなのかは、意見がわかれるような気がします。

```nim:index.nim
win.on("closed", proc () =
  win = nil
)
```

公式のドキュメントの翻訳だと入れてはいないですね。

https://www.electronjs.org/ja/docs/latest/tutorial/quick-start

なんにせよ、nimで、electronを動かすメリットがどの程度あるのかわかりませんが、参考になれば幸いです。