読者です 読者をやめる 読者になる 読者になる

SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

JXCoreを使ってJavaScriptのコードをネイティブコードにパッケージ化する

Node.js

JXCoreというNode.js派生プロジェクトを使い、JavaScriptのコードをネイティブコードとしてのパッケージングするのにつかってみました。
JSで作ったちょいスクリプトの配布とかで便利かもしれません。

JXCoreとは

Node.jsからフォークしたプロジェクトとしてはio.jsが有名ですが、これもNode.jsからフォークしたものの一つ。

以下のような特徴があります。

  • Node.jsとの100%の互換性。Node.jsに独自機能を追加。
  • マルチスレッド動作対応
  • プロジェクト全体をパッケージとして一つのファイルにまとめる事が可能
    • ネイティブコードとしてのパッケージングも可能
  • JavScriptエンジンの切り替え可能
  • モバイルへの対応
    • AndroidiOS向けのバイナリもあるみたい
  • パッケージマネージャが本体に統合されている

いろいろな機能がありますが、今回はネイティブコードとしてのパッケージングだけ使ってみたいと思います。

ダウンロード

以下のページからダウンロードできます。
インストーラも、各プラットフォームごとのバイナリもあります。

Downloads | JXcore
今回は直接バイナリを使ってみます。
Windows ia32 (V8)」をダウンロードしました。

使ってみる

JavaScriptの実行

以下のようにjxコマンドでJavaScriptのコードを実行できます。

jx app.js

f:id:minami_SC:20150906202613p:plain

この辺は、Node.js使うときと同じ感覚です。

ネイティブコードとしてパッケージングしてみる

続いて、本題のjsコードのネイティブ化をしてみたいと思います。
といっても、やることは少しだけ。
JXコマンドを、packageオプションをつけて実行します。ネイティブコードとしてパッケージングする場合は、nativeオプションも追加で以下のように呼び出します。

jx package [スクリプトのエントリポイント] [出力するファイル名] -native

これだけで、単一のバイナリで実行できる形にパッケージングしてくれます。


nodeのプロジェクトに、パッケージング用のタスクを追加する

Nodeからこっちに乗り換える、というのは抵抗があります。
ですが、JXCoreはNode.jsとの互換性があるので、Node.js用に作ったプロジェクトに、JXCoreを使ったパッケージング用のタスクを追加して使う、というのもアリかもしれません。

ということで、package.jsonを使って、JXCoreでネイティブ化するためのタスクを追加してみたいと思います。
サンプルとして、ただのHelloWorldなプロジェクトに追加してみます。

プロジェクト構成

f:id:minami_SC:20150906202646p:plain
こんな感じのプロジェクト構成です。
binフォルダ以下に、JXCoreのバイナリを置いておきます。

app.js

本体のコードはconsole出力だけ。

console.log('Hello world');
package.json
{
    "name": "JxcoreTest",
    "version": "0.0.0",
    "description": "JxcoreTest",
    "main": "app.js",
    "scripts": {
        "start": "node app.js",
        "startJx": "bin\\jx_win32v8\\jx app.js",
        "pack": "bin\\jx_win32v8\\jx package app.js JxcoreTest -native"
    }
}


以下のコマンドで、package.jsonに定義したネイティブ化するためのタスクを実行します。

npm run pack

こういうexeファイルが出来上がります。
f:id:minami_SC:20150906202656p:plain

普通に実行できるexeとなりました。
(コンソールの出力結果が見えるように、コマンドプロンプトから実行してます。)
f:id:minami_SC:20150906202702p:plain


もうちょい複雑なケース

npmで取得した、依存するライブラリがあるような場合でも、依存関係まで含めてパッケージングすることができます。

express-generatorで生成したプロジェクトでも、依存しているライブラリまで含めて、単一のバイナリに出来ました。

プロジェクト全体

f:id:minami_SC:20150906202711p:plain

ちなみに、express-generatorではエントリポイントはbin/wwwというファイルになります。
ですが.js以外の拡張子のファイルを、「jx package」のコマンドに渡すと以下のようなエラーで止まってしまいます。
f:id:minami_SC:20150906203211p:plain
ということで、エントリポイントのファイルはwww.jsという名前にリネームしてます。

package.json
{
    "name": "ExpressTest",
    "version": "0.0.0",
    "private": true,
    "scripts": {
        "start": "node ./bin/www.js",
        "startJx": "bin\\jx_win32v8\\jx bin\\www.js",
        "pack": "bin\\jx_win32v8\\jx package bin\\www.js ExpressTest -native"
    },
    "dependencies": {
        "body-parser": "~1.12.0",
        "cookie-parser": "~1.3.4",
        "debug": "~2.1.1",
        "ejs": "~2.3.1",
        "express": "~4.12.2",
        "morgan": "~1.5.1",
        "serve-favicon": "~2.2.0"
    }
}

出来上がったexeをダブルクリックでサーバーが起動します。
f:id:minami_SC:20150906203344p:plain