このページの本文へ

Electronよりもお手軽に!NW.jsならデザイナーでもデスクトップアプリが作れる

2017年01月11日 04時00分更新

文●Julian Motz

  • この記事をはてなブックマークに追加
本文印刷
Webの技術でデスクトップアプリが作れるフレームワークといえばElectronが有名ですが、より手軽に使えるのがNW.jsです。デザイナーでもちょっとしたデスクトップアプリならすぐに作れちゃいますよ。

NW.jsは、HTML、JavaScript、CSSといったWeb技術を使ってネイティブアプリを作るフレームワークです。一番単純なケースだと、手慣れたワークフローでWebアプリを作り、最後にジェネレーターですべてをコンパイルして、ブラウザー同様にWebアプリを表示できるネイティブアプリを作ります。このようなアプリケーションは「ハイブリッドアプリ」と呼ばれます。

ハイブリッドアプリがすばらしいのは、単になじみのある言語(HTML、JavaScript、CSS)で書けるというだけでなく、本質的に次のような普通のWebアプリよりも優れた点があるからです。

  • ブラウザーの種類とバージョンをコントロールできる(どのブラウザーから実行されたかが分かる)。NW.jsハイブリッドアプリは、Google Chromeで使われているオープンソースのブラウザーChromiumを使って表示されるので、Chromeで動くアプリならばNW.jsでも動く
  • ビューポート(viewport)をコントロールできる。たとえば、固定、最小化、最大化などのサイズの定義ができる
  • ローカルファイルに関する同一生成元ポリシー(same-origin policy)の制約がない。ファイルシステムからローカルファイルを開く際に同じフォルダーに置かれていないファイルへのXMLHttpRequestリクエストはブラウザーにブロックされるが、NW.jsアプリでは無効にできる

さらに、使用できるカスタムAPIには以下のようなメリットがあります。

  • Node.jsとの統合
  • クリップボードへのアクセス
  • ファイルシステムへのアクセス
  • ハードウェアへのアクセス(例:プリンターの一覧を取得する)
  • トレイアイコン
  • ファイル選択ダイアログのカスタマイズ
  • シェルとの統合(標準のファイルエクスプローラやブラウザーでファイルやURLを開く)
  • ウィンドウの閉じるボタン、メニューバー、コンテキストメニュー類を、全体的にカスタマイズできるオプション
  • 拡大縮小のレベルの取得や設定ができる

すごいでしょう? それでは始めましょう。この記事は、ハイブリッドアプリを実際に作りながらNW.jsを理解できるように書いていきます。記事で製作したサンプルアプリはGitHubに掲載してあります。

Electronと比較してNW.jsの優れたところ

最初に言っておきますが、ハイブリッドアプリのためのフレームワークはNW.jsだけではありません。Electronというライバルがいます。NW.jsから2年遅れて2013年の登場ですがGitHubによって開発されていることから、急速に知られるようになりました。この2つの違いに興味があることでしょう。以下がElectronに対してNW.jsが優れているところです。

  • chrome.*APIのサポート:APIでブラウザーとやり取りできる(さらに詳しい情報はNW.jsの公式ドキュメントを参照)
  • Chromeアプリのサポート:ChromeアプリはWebの言語で書かれたアプリケーションパッケージのこと(詳しくはChrome開発者ドキュメント参照)。ChromeアプリはNode.jsと統合できず、Chrome Webストアで配布されるのでNW.jsとは異なる。Chromiumは2018年8月でサポートを終了するが(Chromium Blog)、『NW.js will continue supporting Chrome Apps』によればNW.jsは引き続きChromeアプリのサポートを継続する
  • NaCl(ネイティブクライアント)とPNaCl(ポータブルネイティブクライアント)アプリケーションのサポート:パフォーマンスに主眼を置き、主にC/C++言語で書かれている(NW.jsで使う方法はNW.js Documentation参照)
  • V8スナップショット(コンパイル)でアプリのソースコードを保護:アプリのコードはnwjcツールでネイティブコードにコンパイルされる(詳しくはNW.js Documentation参照)
  • ビルトインのPDFビューワー
  • 印刷プレビューの表示
  • Web WorkerでのNode.jsの動作をサポート:マルチスレッドのアプリを書くときに使う

しかし、Electronにも注目すべき優れた点があります。

  • ビルトインのauto-updater(自動アップデート)モジュール:NW.jsにおけるauto-updaterについてはこちらを参照
  • リモートサーバーへのクラッシュレポート自動送信:NW.jsの場合はローカルファイルに記録するのみで、手動で送信

また、根本的な違いもあります。NW.jsアプリはエントリーポイントとしてHTMLファイルを指定します。このHTMLファイルを直接GUIから開きます。

一方、Electronアプリは、エントリーポイントとしてJavaScriptファイルを指定します。このJavaScriptファイルは別のメインプロセスとして開いてから、GUIでHTMLファイルを開きます。つまり理論上はGUIのないElectronアプリが実行できます。GUIを終了してもメインのプロセスは終了しません。APIのメソッドで終了する必要があります。

ElectronはJavaScriptで書かれたGUIを使用しないデスクトップアプリへの扉を開きましたが、HTMLベースのアプリを表示したいだけなら、おそらくNW.jsアプリのほうが簡単に構築できます。

注:もしElectronのほうがメリットが大きいと感じたら『Create Cross-Platform Desktop Node Apps with Electron』を参照してください。

デモアプリケーションを作る

それでは、コンパイルしてネイティブアプリ化するアプリケーションを作っていきましょう。Webアプリを作る方法はたくさんあります。いろいろなJavaScript派生言語(TypeScript、CoffeeScriptなど)、モジュールローダー(RequireJS、Webpack、SystemJSなど)、フレームワーク(AngularJS、React、Vue.jsなど)、プリプロセッサー(SCSS、LESS、Hamlなど)など、それぞれお気に入りがあることでしょう。ここでは基本的なHTML、CSS、JavaScript(ES6標準)の技術のみを使用します。

すべてのケースで使えるようなNW.jsのボイラープレート(定型文)はありません。すべて特定のフレームワーク、モジュールローダー、プリプロセッサー向けになっています。例では自力でシンプルなNW.jsアプリをゼロから作ります。そのほうが理解しやすく、あとで必要に合わせて改造したりボイラープレートへ乗り換えられます。

プロジェクトの構成

最初に、プロジェクトの骨組みとファイルを作ります。

nw.js-example/
├── src/
│   ├── app/
│   │  └── main.js
│   ├── assets/
│   │  └── icon.png
│   ├── styles/
│   │  └── common.css
│   ├── views/
│   │  └── main.html
│   └── package.json
└── package.json

それぞれについて説明します。

  • src/:作成するアプリのソースファイル
  • src/app/:必要なJavaScriptファイル
  • src/assets/:画像ファイル。この例ではicon.pngのみで、ウィンドウのアイコンとして表示され、四角形でなければならない
  • src/styles/:通常はSCSSまたはLESSのファイル。今回の例では単純なCSSファイルのみ
  • src/views/:HTMLのビュー
  • src/package.json:NW.jsアプリのマニフェストファイル(manifest formatを参照)。アプリの依存オブジェクトもここで指定
  • package.jsonnpmパッケージファイル。ビルドのワークフローで必要なファイルで、ここで実際のNW.jsアプリでは必要ない依存オブジェクト、たとえばビルド時の依存オブジェクト(dependency)を指定

マニフェストファイルを作る

プロジェクトの骨組みとファイルができたので、NW.jsのマニフェストファイルsrc/package.jsonの作成から始めます。公式ドキュメントによれば必要なのはたった2つで、アプリ名のnameと、エントリーポイントのHTMLファイルのパスのmainです。ただし、ここではさらにウィンドウアイコンのファイルパスと、意図しない表示を避けるための最小の幅と高さの指定を加えます。

{
  "name":"nw.js-example",
  "main":"views/main.html",
  "window":{
    "min_width":400,
    "min_height":400,
    "icon":"assets/icon.png"
  }
}

これだけです! mainへのパスはマニフェストファイルから見た相対パスなので、以降このアプリは最初にsrc/views/main.htmlを開きます。

メインビューを作る

この時点で、to-doアプリをプログラミングすることだってできます。しかし、この記事の目的はNW.jsとその機能の紹介なので、アプリは読者のみなさんに作成してもらいます。Node.jsとの統合、クリップボードへのアクセスといったNW.jsの機能を使ったサンプルプロジェクトNW.js-examplesがGitHubにあります。読者のみなさんが試しに作るアプリでも自由に使ってください。

なにを作るにせよ、アプリのエントリーポイントとして最低限src/views/main.htmlファイルを作る必要があります。

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>NW.js-example | main</title>
    <link rel="stylesheet" href="../styles/common.css">
</head>
<body>
    <h1>Hello World :-)</h1>
    <script src="../app/main.js"></script>
</body>
</html>

実際のアプリではおそらくほかにもビューが必要で、Ajaxで読み込むことになるでしょう。単純化のために、ネイティブのリンクを作ってほかのHTMLファイルを参照することも可能です。たとえば、次のようにします。

<a href="something.html">Something</a>

そして、src/views/の中にsomething.htmlファイルを作ります。この例で実際に使ったものはこちらです。

NW.jsのインストール

マニフェストとメインビューを含むNW.jsプロジェクトができました。ようやく、NW.jsを直接実行して、複数OS対応のネイティブアプリを生成するビルドプロセスが実装できます。

以下の2つのパッケージが必要です。

この2つは実際のアプリとは関係が無いので(開発用と本番用のビルドのためだけなので)、ルートフォルダーのpackage.jsonに、devDependenciesとして必須項目nameversionと一緒に記述します。

{
  "name":"nw.js-example",
  "version":"1.0.0",
  "devDependencies":{
    "nw":"^0.18.2",
    "nw-builder":"^3.1.2"
  }
}

devDependenciesをインストールするため、プロジェクトのルートフォルダーで以下を実行します。

$ npm install

できました! それではビルドしましょう。

パッケージ化と配布

パッケージ化を楽にするためpackage.jsonファイルにnpmスクリプトを加えます。右側にはショートカット、左側にはnpm runコマンドの使用が定義されたCLIコマンドが実行できます。開発用と本番用のために2つのscriptsを追加します。

{
  "name":"nw.js-example",
  "version":"1.0.0",
  "devDependencies":{
    "nw":"^0.18.2",
    "nw-builder":"^3.1.2"
  },
  "scripts":{
    "dev":"nw src/",
    "prod":"nwbuild --platforms win32,win64,osx64,linux32,linux64 --buildDir dist/ src/"
  }
}

直接NW.jsを実行する

NW.jsアプリを直接実行するには、単に次のようにします。

$ npm run dev

このショートカットは、先ほどnwパッケージを使いscriptsdevと定義したコマンドを実行します。src/views/main.htmlを表示した新しいウィンドウが直接開きます。

本番環境へのビルド

本番環境へのビルドは、Windows、Linux、Mac OSに対応するファイルを出力できるnw-builder使います。例では、すべてのプラットホームの32ビット/64ビット版両方に対応するパッケージをビルドします。現在のところMac OS向けの32ビット版はレガシーモードでしかビルドできません(GitHubを参照)ので、64ビット版のみビルドします。

本番用のビルドは、以下を実行するだけです。

$ npm run prod

NW.jsを直接実行したときと同じく、先ほどscriptsで定義したCLIショートカットコマンドを使います。

これにはしばらく時間がかかります。

Building NW.js

いったん完了したら、dist/フォルダーは、次のようになっています。

dist/
└── nw.js-example/
    ├── linux32/
    ├── linux64/
    ├── osx64/
    ├── win32/
    └── win64/

すばらしい、ほとんど完成しました!

テストとデバッグ

手動での実行

NW.jsはChromiumベースなので、手動でのテストはChrome同様にシンプルです。外観であれ、機能であれバグに遭遇したら、F12キーもしくは下記コマンドを使えばデベロッパーツールを開けます。

nw.Window.get().showDevTools();

NW.js Developer Tools

なお実行には、SDK build flavorが必要です。もし本番アプリでデベロッパーツールを無効にしたいなら、別のflavorを使ってNW.jsをビルドするか、F12キーを無効にします。

自動化

幸いにもユニットテストは広く自動化されていて、いちいち手動でテストすることなくさまざまな環境下での動作確認ができます。

Karma and Jasmine

もしアプリがNW.js専用のAPIメソッドを使っていなければ、理屈上は通常のWebアプリ製作ワークフローが使えます。たとえば、テストフレームワークとしてJasmine、テストランナーとしてKarmaを組み合わせて使うなどです。

しかし、もしNW.js専用のAPIメソッドを使っているなら、NW.jsアプリで専用のAPIメソッドが正しく定義されているかどうかテストしなければなりません。1つの方法は、Karmaでkarma-nodewebkit-launcherのようなNW.jsランチャープラグインを使うことです。このプラグインはKarmaのほかのブラウザープラグインと同様です。チェックのためにNW.jsのコンテナ内で自動でアプリを開き、自動で閉じます。

しかし、NW.jsはPhantomJSなどとは違って、画面表示なしのアプリ(headless)ではないので、常にディスプレイが必要です。つまり純粋なCLIサーバーだけでテストするのは不可能です。幸い、こうした場合にXvfbを使えばディスプレイのシミュレーションができます。たとえば、XvfbはTravis CIで動作します。Jenkinsで使うならばXvfbプラグインをインストールします。詳しくはGitHubを参照してください。

最後に

この記事で、NW.jsの優れたところやそのユースケースに気づいてもらえたら幸いです。HTMLファイル入りの.zipフォルダーで配布されてファイルシステムから実行するようなアプリより、ハイブリッドアプリのほうが優れている理由はいくらでもあります。またNW.jsはネイティブアプリの置き換えにもなります。開発者が複雑なGUIに煩わされずに済み、ビデオプレーヤーのようなビルトイン機能がたくさん使えます。実行環境が検出できるので、普通のWebサーバーと、NW.jsを入れたクライアント側マシンのどちらでも動くアプリも開発可能です。ちょっとした工夫とパワフルなChromiumエンジンのおかげで、ユーザーはネイティブアプリとの違いにほとんど気がつかないでしょう。

新規にNW.jsプロジェクトを作るときは、最初に使いたいフレームワーク、モジュールローダー、プリプロセッサーを、自分の慣れも考慮して決めます。次に、プロジェクト要件を満たすNW.jsのボイラープレートを探します。ぴったりのものが無ければ、ベースとしてこの記事で作成したアプリも使用できます。

※本記事はTim SeverienJoan Yinが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者の皆さんに感謝します。

(原文:Building a Cross-platform Desktop App with NW.js

[翻訳:西尾健史/編集:Livit

Web Professionalトップへ

WebProfessional 新着記事