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

  • 21
    いいね
  • 0
    コメント

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を入れたらいいのではないですか?とコンパイラに言われるので、入れてみたら引っかかるという罠でした。