【Node.js】NW.jsでnodeなしで動くアプリを作りたい！

大幅に遅れましたが、この記事は [株式会社ピーアールオー（あったらいいな！を作ります） Advent Calendar 2019](https://qiita.com/advent-calendar/2019/pro-japan1) の19日目の記事です。

# はじめに
最近、お仕事でもNode.jsを使うことが増えてきました。
JSベースなので結構雑にツールを作れてありがたいのですが、そのツールを誰かに連携する時に相手方もNode.jsを入れてもらう必要があって連携は中々ハードル高めです。
という訳で、今回はWindowsでNode.jsで作成したものをスタンドアロンアプリとして出力できるNW.jsを触ってみました。

# 実行環境
OS: Windows 10 Pro v1903
node.js: v10.13.0
NW.js: 0.43.2
NW-Builder: 3.5.7

# 導入手順…と言いたいところですが
NW.jsの導入についてはQiita上にかなりしっかりまとめていただいている記事が存在します。

[NW.jsでデスクトップアプリの夢を見る！](https://qiita.com/Yanase-Takuma/items/b28b528a9c34ad21599e)

大まかな流れは上記通りなので、細かい手順は省略して、実際に触ってみて躓いたりしたところをまとめてみます。


## まずはNW.jsを動か…せない！
もう新しいものに触ると**必ず**起こる現象ですね。
今回は以下を通らせるために苦戦しました。

```
nw ./src
```

当然といえば当然ですが、```npm install --save```でインストールしたモジュールにはパスが通っていません。

nwjs, nw-builderの各実行ファイルはプロジェクト直下の```./node_modules/.bin/```配下にインストールされてますので、
実際に実行する場合はパスを指定して叩く必要があります。
例えば、プロジェクトフォルダ直下で実行する場合は

```
NW.js
./node_modules/.bin/nw

nw-builder
./node_modules/.bin/nwbuilder
```

という感じですね。global installしてしまえば解決しちゃいますが…。

package.jsonのscriptに実行エイリアスを書く場合は、プロジェクト直下のpackage.jsonに記載する必要があります。
また、mainを``src/.../index.html``のように直下からの相対パスに直しておきましょう。

よく見るおすすめ構成ではpackage.jsonが二重になっているため、そこ起因で変な事が起きやすいです。
上手くコマンドが通らないときはまずpackage.jsonを疑ってみるのが良さそうです。

## 沈黙を保つDevTools
NW.jsはChromiumベースなので、Chromiumで使用できるDevToolがそのまま使えるとのこと。
F12を押せばお馴染みのDevToolが…**出てこない！**

NW.jsではDevToolsさんは通常のNW.jsをインストールしただけでは働いてくれません。（2019/12時点）

https://github.com/nwjs/nw.js/issues/4383
上記issueで回答されているように、DevToolsを使用したい場合は以下のコマンドを使用してSDKモードでインストールする必要があります。

```
npm install nw --nwjs_build_type=sdk
```

ちなみに、このモードのままビルドを実施すると出力されたアプリでもDevToolsが利用可能になります。
出力されたアプリでDevToolsを使われたくない場合はビルド前に切り替えておきましょう。

## ビルド時に失踪するNPMパッケージ
開発環境で動作確認OK！ビルドも正常完了！当然、出力されたアプリも**動かない！ヨシ！**…あれ？

こういう時は落ち着いてSDKモードで再度アプリを出力してDevToolsを起動してみましょう。
今回の場合は以下のエラーが発生していました。

```
Uncaught Error: Cannot find module '(モジュール名)'
```

なぜか開発環境では動いていたはずモジュールが失踪してしまってますね…。
この場合、疑うべきはNPMパッケージのインストール場所です。

先ほど紹介した手順でプロジェクトを作成した場合、大体以下のプロジェクト構成になっていると思われます。

```
/project
  + /node_modules
  + /src
    + (index.js などなど)
    + package.json
  + package.json
```

このプロジェクト構成では``/project``直下は、NW.jsでbuildするために必要な外殻であり、
動かしたいプロジェクトの実体は``/src``配下です。

ここまで言えばもうわかる方も多いと思いますが、今回のケースでは**/project 直下でNPMインストールをしてました。**
nw-builderでビルドするのは当然``/src``配下なのでビルド後のアプリには``./project/node_modules``に含まれてるNPMパッケージは含まれていません。そのため、今回の事象が発生しました。~~でもやりたくなるじゃん！~~

正しく動かすためには、``npm install``は、``/src``配下で実施する必要があります。
（package.jsonが``/src``配下にあるんですから当然と言えば当然ですが…。思い込みって怖い。）

# MacOS向けのビルドが通らない
NW-builderではWindows, MaxOSX, Linux用のアプリをそれぞれ出力することが可能ですが、
MaxOSX用のビルドは以下のエラーでこけます。

```
 UnhandledPromiseRejectionWarning: Error: EPERM: operation not permitted
```

nw-builderのissueを確認する限り、どうやらWindows10のシンボリックリンクの権限の問題のようです。
https://github.com/nwjs-community/nw-builder/issues/463

即時解決は難しかったので、今回はdocker上のlinuxで動かすことで解決してしまいました…。~~やはりdockerはすべてを解決する~~

# アプリケーションサイズが大きすぎる
これはそのままです。Chromiumを動かすためのドライバーがセットで入ることになるので、非常にサイズが大きくなります。
Hello Worldを出力するだけの簡単なWindowsアプリでどのくらい大きくなるかを確認してみると、

プロジェクト本体：108 B　→ 出力後：**298 MB**

これだけ膨れます。~~増えるワカメみたいですね。~~

地がこれだけ大きいので、重い事で有名なNPMパッケージをアプリ内に大量に取り入れるのはあまり得策ではなさそうです。
NPMパッケージをあまり使わない、小規模なツールを作成するために使用するのが向いていそうに思えます。

# おわりに
色々躓いたり引っかかったところもありましたが、Node.jsの資産を活かしつつ相手の環境を縛らない上にUIまで作れちゃうNW.js、中々いい感じです。一方で、大きくなりがちなサイズやChromiumに依存している所を見ると、頒布向けというより内製ツール向けな印象も受けました。
とにかくプロジェクト作成から出力までが手軽なので、簡単な内製ツールで、UIが必要な場合などは使ってみるのどうでしょうか？