連続で忙しい日にアドベントカレンダー入れるんじゃなかった泣
と思いながらGodotでNimを使ってゲームを作ろうかと思ったのですが
すでに似た記事があったためNim + Electronに変更します 笑
概要
実行環境
・M1 MacbookAir(2020)
・OS macOS BigSur 11.5.2
・メモリ 16GB
ディレクトリ構成
├── index.html
├── main.js ・・・コンパイル結果
├── main.nim
└── package.json
package.json
{
"name": "electron-quick-start",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"repository": "https://github.com/electron/electron-quick-start",
"keywords": [
"Electron",
"quick",
"start",
"tutorial",
"demo"
],
"author": "GitHub",
"license": "CC0-1.0",
"devDependencies": {
"electron": "^12.0.1"
}
}
実行の手順
main.nimに処理を記述して以下でjsにコンパイルしてnpm startで実行できます。
$ npm install
$ nim js -d:node -o:main.js main.nim
# アプリ起動
$ npm start
NimでのElectron記述
jsライブラリのimport
まずelectronがjs製なため、jsの関数やイベントをロードする必要があります。
ここら辺は脳死で書いてしまっていいかと思います。
(動くまでに結構時間がかかりました...)
main.nim
import jsffi
{.emit: """
const electron = require('electron')
const path = require('path')
const url = require('url')
const net = require('net');
""".}
var
electron {. importc, nodecl .}: JsObject
path {. importc, nodecl .}: JsObject
url {. importc, nodecl .}: JsObject
console {. importc, nodecl .}: JsObject
process {.importc, nodecl.}: JsObject
net {.importc, nodecl.}: JsObject
dirname {.importc: "__dirname", nodecl.}: JsObject
ウィンドウの起動設定
main.nim
let app = electron.app
var mainWindow: JsObject
proc createWindow() =
# ウィンドウサイズを指定してjsnewを使ってウィンドウを作成
mainWindow = jsnew electron.BrowserWindow(JsObject{width: 800, height: 600})
mainWindow.loadURL(url.format(JsObject{
pathname: dirname.to(cstring) & "/index.html",
protocol: "file".cstring,
slashes: true
}))
mainWindow.on("closed", proc () =
mainWindow = nil
)
イベントハンドラ
ready(起動時)
main.nim
app.on("ready", createWindow)
window-all-closed(Windowが全部閉じられた時)
main.nim
app.on("window-all-closed", proc () =
if process.platform.to(cstring) != "darwin":
# 終了処理
app.quit()
)
ここでdarwinとしているのはos判定なので、
NimのOSプラットフォームを見て必要であれば追加してください。
バックグラウンドからアクティブにされた時
main.nim
app.on("activate", proc() =
if mainWindow == nil:
createWindow()
)
activateにcreateWindowを書く必要があるのは
macOSなどでバックグラウンド起動時にアイコンから起動で
ウィンドウを再生成する場合があるためらしいです。
以下、main.nimの全文です。
main.nim
import jsffi
{.emit: """
const electron = require('electron')
const path = require('path')
const url = require('url')
const net = require('net');
""".}
var
electron {. importc, nodecl .}: JsObject
path {. importc, nodecl .}: JsObject
url {. importc, nodecl .}: JsObject
console {. importc, nodecl .}: JsObject
process {.importc, nodecl.}: JsObject
net {.importc, nodecl.}: JsObject
dirname {.importc: "__dirname", nodecl.}: JsObject
let app = electron.app
var mainWindow: JsObject
proc createWindow() =
mainWindow = jsnew electron.BrowserWindow(JsObject{width: 800, height: 600})
mainWindow.loadURL(url.format(JsObject{
pathname: dirname.to(cstring) & "/index.html",
protocol: "file".cstring,
slashes: true
}))
mainWindow.on("closed", proc () =
mainWindow = nil
)
app.on("ready", createWindow)
app.on("window-all-closed", proc () =
if process.platform.to(cstring) != "darwin":
app.quit()
)
app.on("activate", proc() =
if mainWindow == nil:
createWindow()
)