React+Electronアプリを作ってみよう
Tags: react, electron, japanese
Published: 2018-03-05 18:26:06

---
title: React+Electronアプリを作ってみよう
published: true
description: How to create React and Electron application in quickly
tags: React, electron, Japanese
---

こんにちは。前置きは抜きにすぐ作ります。 
# Create Application
## 01: create-react-app
まずはcreate-react-appです。なかったら`npm install -g create-react-app`してください。
うまくいったら`yarn start`で起動しましょう。しましたか？うまくいってるのを確認したら即刻ジョブ止めましょう。もう二度と`yarn start`を実行することはありません。

## 02: install Some Package
以下のパッケージをインストールしてください。最新ので問題はないはずです。すべてインストール時に`--dev-dependencies`を付けることを忘れないでください。まあ忘れてもいいです。

* electron
* npm-run-all

## 03: setting up Electron
[こちらのgistを参照してください。](https://gist.github.com/origamium/7d8edd3960fa7c3f813a8f3b25d8c5d7)
次に`electron-starter.js`、`electron-wait-react.js`、`application.js`を`src/`以下に配置してください。色々書いてありますが後ほど説明します。

## 04: package.json
`package.json`にmainとhomepage、そしてscriptsに追記します。以下のようになればいいです。

```json
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "main": "src/electron-starter.js",
  "homepage": "./",
  "dependencies": {
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-scripts": "1.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "electron:dev": "electron .",
    "dev": "npm-run-all --parallel electron:dev start"
  },
  "devDependencies": {
    "electron": "^1.8.2",
    "npm-run-all": "^4.1.3",
  }
}

```
いくつか興味深いところはありますが、後ほど解説します。今はこれをただ受け入れてください。でも名前は好きに変えてもいいのよ。

## 05 start!
ではいよいよ動かす時が来ました。`yarn dev`あるいは`npm run dev`を実行し、ブラウザとElectronが立ち上がって、同じ画面が映っていることを確かめてください。
![](https://thepracticaldev.s3.amazonaws.com/i/wq2igybejlct8djihkwi.jpg)
また、もう既にこの時点でElectron側にもホットロードが機能していることも試してみましょう。`src/App.js`の構文をわざと間違えて、ブラウザとElectronの両方の画面がエラーになることを確認するのです。  
ホットロードまで確認したら、おめでとうございます！あなたはReactでElectronアプリケーションを作ることに成功しました。
さて、いくつか気になる所があったはずです。それらは次の項で説明します。

# Explanation Create Application
## Structure
今回のElectronアプリケーションの構造は比較的単純です。`react-scripts`によって起動したWebサーバに、Electronがアクセスして表示しているだけです。本当にこれだけです！図にするまでもありませんが、図にしてみましょう。

![](https://thepracticaldev.s3.amazonaws.com/i/tzgkfp6m0fmwkt4jfzfm.jpg)

ところで、`react-scripts`と`electron`は`npm-run-all`によってそれぞれ起動されます。このとき２つは同時に起動しています。

## Security Warning?
まず、あなたが最新のElectronで開発している場合、`yarn dev`あるいは`npm run dev`を実行した場合にconsoleに次のような警告が出ているはずです。

```
Electron Security Warning This renderer process has Node.js integration enabled and attempted to load remote content. This exposes users of this app to severe security risks.
For more information and help, consult https://electronjs.org/docs/tutorial/security
```

これは要するに「なんかWebページをElectronで見てるけどここに悪意あるコード仕込まれてたらすごいやばいことが起きるぞ！」という警告です。
なぜ、この警告が出たかは自明ですね？今回の（開発時の）設定では、静的なHTMLやJavascriptファイルではない、localhostに立ち上がっているWebサーバ `localhost:[port number]` をElectronでアクセスしているために、このエラーが発生しています。
勿論ビルド時にはWebサーバーではなく、ビルドした静的なhtml, css, javascriptファイルをElectronに読ませるため、このセキュリティ警告は発生しません。安心してください。あなたのElectronアプリケーションは（今のところ）安全です！

## package.json
私は先程、何も言わずにしれっと`package.json`に、以下の項目を追加していました。
```json
"homepage": "./"
```
もしあなたがこの項目を`package.json`に追加していないのならば、すぐに追加すべきです。この項目は開発時には効果をまったく発揮しませんが、ビルド時にはとても重要な項目となります。
ネタバレをしてしまうと、`react-scripts build`を実行した際、出力された`index.html`が`package.json`のあるディレクトリをベースに、同じくビルドされたJavascriptファイルやCSSファイルへアクセスするために設定されています。
少しわかりづらいですか？まあ要するにこの設定がないと`react-scripts build`の実行時にうまくファイルたちが関係を持てない、という具合に覚えておけばいいです。

# Build and Release
## 01 setup
さて、いよいよ時が来て、あなたのElectronアプリケーションをリリースしたい時がやってきました。
今回はだるいのでautoupdater等の解説はしません。しかし、npmで`electron-packager`と`asar`をdevDependenciesとしてインストールしておいてください。
かつ、これはかなり大切なことなのですが、今あなたの`package.json`の`"dependencies"`には`react`、`react-dom`、`react-scripts`の3つが入っているはずです。（何も手を加えていないのであれば）
それをすべて、`"devDependencies"`に黙って移動させてしまいましょう！なに、バレませんよ。

```json
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "main": "src/electron-starter.js",
  "homepage": "./",
  "dependencies": {
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "electron:dev": "electron .",
    "dev": "npm-run-all --parallel electron:dev start"
  },
  "devDependencies": {
    "electron": "^1.8.2",
    "npm-run-all": "^4.1.3",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-scripts": "1.1.1"
  }
}

```
ああ、なんてこと…`"dependencies"`が空っぽになってしまいました。しかしご安心ください。これはこの後に効いてくる、とても効果的な、最高の設定です。

## 02 build
`npm run build`あるいは`yarn build`を実行してください。

## 03 packager
さて、`electron-packager`の設定を忘れていました。追加しましょう。`package.json`のscriptsに以下の一文を追加します。

```json
    "package": "electron-packager . my-app --platform=all --arch=x64 --prune --out=release --overwrite"
```

さて、実行してみましょう。`yarn package`あるいは`npm run package`の出番です。
時間がかかります。3分ぐらいから5分とか。気長に待ちましょう。

## 04 run!
パッケージングがうまくいっていれば、`release`ディレクトリの中に各種バイナリが発生しているはずです！
ただし、macOSとlinuxの場合、wineがないとwin32向けビルドが発生しません。同様に、Windowsでは管理者権限のあるコンソールでないとmas(macOS)向けビルドが発生しません。（darwin向けビルドはなぜかできません）
この記事を見ているみなさんのOSは仮定しません。自分の環境で動きそうなバイナリを探してください。

![](https://thepracticaldev.s3.amazonaws.com/i/sfnxyvj1kpafhmlpgdzd.jpg)

わはー！動きましたね！そして、http://localhost:5000 にアクセスしても、Webサーバーが立ち上がっていないので何も表示されませんし、consoleでSecurity Warningが発生していないことを確認しましょう。静的なファイルを読み込んでいる証拠です。
…さて、これでビルドは終わりではありません。もう少しだけ、先に進んでみましょう。

# 05 delete unnecessary files
`release`ディレクトリにぶちまけられた各種バイナリには、無駄なファイルが潜んでいます。特に、あなたがエディタに使っているのがVisual Studio Codeだった場合、`.vscode`などがそのままバイナリに入っています。
…バイナリという言葉に少々語弊がありますが。とにかく、以下のディレクトリに注目してください。
```
windows : /release/[app-name]-win32-x64/resources/app
darwin  : /release/[app-name]-darwin-x64/[app-name].app/Contents/Resources/app
mas     : /release/[app-name]-mas-x64/[app-name].app/Contents/Resources/app
linux   : /release/[app-name]-linux-x64/ 
```
appディレクトリの中です。`.gitignore`や、あろうことか`src`ディレクトリまでそのまま入ってしまっています…これは問題です！消してしまいましょう。ただし、srcディレクトリには注意してください。`electron-starter.js`と`electron-starter.js`は消してはいけません。これらは開発時と同じく、ビルド後のElectronもアクセスするファイルです。それ以外は消してしまいましょう。

```
app
│ package.json
│
├─build
├─node_modules
└─src
   │   application.js
   └   electron-starter.js
```

掃除後のディレクトリ構造はこのような状態になっているはずです。おっと、`build`と`node_modules`には基本的に手を出してはいけませんよ。それから`package.json`を消すのもダメです。
(補足：buildディレクトリには各種mapファイルが出力されてもいます。もし実際に配布するのであれば、`~.js.map`と`~.css.map`ファイルを消すのが無難でしょう)
これで実質的な最小の状態になりました。この状態でもアプリケーションが問題なく起動することを確かめておきましょう。

## 06 asar
さて、先程のrelease以下のそれぞれのappディレクトリはこのままでもいいですが、Electronはasarでappディレクトリを圧縮することを推奨しています。一つ前のディレクトリにまでコマンドラインで戻り、appをasarで圧縮します。

``` shell
> asar pack app app.asar
```
のち、appディレクトリを削除します。
この状態でアプリケーションが問題なく起動することを確かめてください。

## 07 zipping application
あとは、releaseディレクトリ以下のそれぞれのディレクトリをZIPかなにかで圧縮すれば、もう配布可能なバイナリになりました。おめでとうございます！

![](https://thepracticaldev.s3.amazonaws.com/i/gilv3q913e4pnil9afy6.jpg)

ただし、darwin(mas)にはアプリに署名をするという大切な工程もありますが、今回は無視しています。各位で調べてください。

# Explanation Build and Release
## Why moved all package from dependencies to devDependencies?(it's important!)
これはかなり奇妙な行動に思えたはずです。なぜすべてのパッケージをdevDependenciesに移動したか？それは配布後のパッケージのサイズに関係してきます。
まず大前提をお話しましょう。今回特に、`react-scripts`はかなり大きなパッケージであるということが関係してきます。`react-scripts`の関係するパッケージはまとめて100MBを超えています。このパッケージを配布バイナリに含めるとなると、それだけで数百MBもサイズが膨れ上がってしまいます。

ところで、アプリケーションとして配布する時、パッケージング前に`react-scripts build`を実行したことを覚えていますか？build実行時に`react`や`react-dom`それらをすべてまとめてbuildディレクトリ以下のファイルにまとめて梱包して出力してくれるのです。これらは裏で`webpack`が動いてくれているからなのですが。
まあそれはさておいて、この時点でbuildディレクトリの中のファイルはnode_modulesとは(ほぼ)関係なしに動いてくれるようになりました。

つまり、`electron-packager`を使ってElectronアプリを梱包する時、もう`react-scripts`は必要ないのです！また、それは`react`と`react-dom`に対しても言えることです。今後導入するであろう`redux`、`react-redux`、`redux-saga`などのパッケージに対しても同様です。***開発時とビルド時にのみ必要なパッケージは、すべてdevDependencies(開発時の依存関係)に入れてしまいましょう。***
devDependenciesに突っ込んだパッケージは、`electron-packager`がすべて取り除いてくれます。


ただし、**例外もあります**。Electronではrenderプロセス――つまりsrc/index.js以下のどこかのタイミング――でNode.jsとそれらを使用したパッケージにアクセスできることをご存知でしょうか？[electron.remote.require()](https://github.com/electron/electron/blob/master/docs/api/remote.md)のことです。
もしあなたがNode.jsを使用したパッケージをelectron.remote.requireを使用して呼び出していた場合、***そのパッケージはdevDependenciesに入れてはなりません***。
なぜならば、そのパッケージは実行時に`node_modules`から呼び出されるからです。

同様に、今回で言えば`application.js`など、Electronが直接読むスクリプトの中で呼び出しているパッケージも同様に***devDependenciesに入れてはいけません***。たとえば、`electron-about-window`などです。
以上のことはかなり注意すべきことです。覚えておきましょう。

## Why don't use `--ignore` option in electron-packager?
…これは本当に私もわからないのですが、Windowsから`--ignore`オプションを使おうとすると、どうしてもエラーが起きてしまって、パッケージングできないという問題があります…未だに不明なのですが、linuxやmacOSをお使いの皆さんなら使えるはずです。都度使ってみてください。正規表現パターンを使用してパッケージング時に不要なファイルを削除できます。また、不要なファイルを全て削除できるなら`--asar`オプションでasarに圧縮するところまで自動でやってくれます。
私はそれがどうしてもできないので、自分でビルドスクリプトを書きました。みなさんも勝手に書くべきです。

# Conclusion
今回、webpackの設定ファイルを一切書いてないことに気付きましたか？かなり込み入ったことをしない限り(ejectを必要としない限り)は、webpackの設定ファイルを一切書くことなくElectronアプリを書けることがわかりましたね。さらにcreate-react-appでは型チェックツールであるFlowもそのまま使うこともできます。
宣伝ではありますが、これとほぼ同様のやり方で[Tsuru](https://github.com/tsuruclient/tsuru)も開発されています。

この記事は[How to build an Electron app using create-react-app. No webpack configuration or “ejecting” necessary.
](https://medium.freecodecamp.org/building-an-electron-application-with-create-react-app-97945861647c)をベースに、さらに踏み込んだ所まで解説した記事です。

# Update
Foremanをnpm-run-allに置換しました。これにより`Procfile`がなくても実行できるようになり、実行スクリプトがすべて`package.json`の`scripts`内におさまり、管理しやすくなります。