Posted at

RustでNode.jsのモジュールを作りElectronで利用する

More than 1 year has passed since last update.

Rustを使ってNode.jsのモジュールを作る方法について書きます。

Neonを使います。

Electronを使ってデータの可視化アプリを作りたいと思って実装中なのですが、データの読み込み時にすでに書いてあるRustのプログラムを流用したいなーということで方法を探していたら、下の記事を見つけました。

Rust と Electron で GUI アプリケーションを作る

RustをElectronアプリケーションに組み込む方法がいくつか紹介されているのですが、この中で、Neonを使ったNative Addonの作成をやってみたので、その手順をメモとして残します。


ElectronとNeonの環境構築

まずはelectron-quick-startのリポジトリをそのままクローンしてきます。

Electronの公式に従って、

$ git clone https://github.com/electron/electron-quick-start

$ cd electron-quick-start
$ npm install && npm start

これでHello, Worldが表示されたElectronアプリケーションが起動することを確認します。

アプリケーションを終了し、次はNeonを用いた開発に必要なものをいれます。

NeonのBUILDING ELECTRON APPSに従って、

$ vi package.json # devDependenciesに2つを追加

"devDependencies": {
...
"electron-build-env": "^0.2",
"neon-cli": "^0.1.17"
}

そして、パッケージをいれます。

$ npm install


Rustを用いたモジュール作成

Rustでモジュールを作っていきます。

今回は、NeonのGitHubのREADMEにある、make_an_arrayを追加していきます。

$ cd node_modules

$ neon new make-an-array # いろいろ聞かれますが全部Enterで

すると、以下のような構造が生成されます。

make-an-array/

├── .gitignore
├── README.md
├── lib/
│ └── index.js
├── native/
│ ├── Cargo.toml
│ ├── build.rs
│ └── src/
│ └── lib.rs
└── package.json

lib.rsとindex.jsを編集します。


lib.rs

#[macro_use]

extern crate neon;

use neon::vm::{Call, JsResult};
use neon::js::{Object, JsArray, JsInteger, JsNumber, JsObject};
use neon::mem::Handle;

fn make_an_array(call: Call) -> JsResult<JsArray> {
let scope = call.scope; // the current scope for rooting handles
let array: Handle<JsArray> = JsArray::new(scope, 3);
try!(array.set(0, JsInteger::new(scope, 9000)));
try!(array.set(1, JsObject::new(scope)));
try!(array.set(2, JsNumber::new(scope, 3.14159)));
Ok(array)
}

register_module!(m, {
m.export("make_an_array", make_an_array)
});



index.js

var addon = require('../native');

exports.make_an_array = addon.make_an_array;


lib.rsにモジュールに追加したい関数を書いて、それをindex.jsでエクスポートします。

次に、electron-quick-start以下に戻り、packege.jsonにビルド用スクリプトを追加します。

$ vi package.json # scriptsにbuildを追加

"scripts": {
"build": "electron-build-env neon build make-an-array",
...
}

最後に、Electronアプリケーションから作ったモジュールを使用するコードを書きます。

今回は短いので、index.htmlのscriptタグ間に挟んでおきます。


index.html

<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
We are using Node.js <script>document.write(process.versions.node)</script>,
Chromium <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</body>

<script>
// You can also require other files to run in this process
console.log(require('make-an-array').make_an_array());
require('./renderer.js');
</script>
</html>


それでは、モジュールをビルドし、アプリケーションを実行します。

$ npm run build

$ npm start

ディベロッパーツールを開いて、Arrayがコンソールに出力されていることを確認してください。

無事、作成したモジュールを利用することができました。


JsArrayが使えなくて詰まった

ちなみに私はmake_an_arrayをREADMEからコピペしたあと、必要なモジュールがわからず少しつまりました。

JsArrayのsetがどうしたら使えるのかわからなかったのです。

調べたところ、GitHubにissueがありました。

https://github.com/neon-bindings/neon/issues/57#issuecomment-310842980

neon::js::Objectを入れて、neon::js::Keyを入れないようにしないといけないみたいです。neon::js::Objectを入れないと、arrayにsetがないよと言われるのですが、そのときに、neon::js::Keyを入れたらいいのではないですか?とコンパイラに言われるので、入れてみたら引っかかるという罠でした。