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を編集します。
#[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)
});
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タグ間に挟んでおきます。
<!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を入れたらいいのではないですか?とコンパイラに言われるので、入れてみたら引っかかるという罠でした。