React+ElectronでHello Worldする

## アプリケーションの作成

通常のReactアプリと同じように、`create-react-app`コマンドで作成します。

```
create-react-app helloworld
```

`helloworld`はアプリ名です。好きに付けてください。この名前がアプリケーションのディレクトリ名になります。以後の操作はこのディレクトリ内で行うので、このディレクトリに移動してください。

```
cd helloworld
```

## 必要なライブラリーのインストール

次にElectronアプリ開発に必要なライブラリーをインストールします。

```
npm install electron electron-packager concurrently --save-dev
```

* `electron` は開発時に実行ファイルをビルドすることなくアプリケーションを実行するためのモジュールです。
* `electron-packager` はスタンドアロン実行可能な実行ファイルを作成するためのモジュールです。
* `concurrently` は複数のコマンドを並行実行するためのモジュールです。


## ビルドスクリプトの編集

`package.json`内の`scripts`ブロックを以下のように編集します。デフォルトの`start`,`build`スクリプトを`react-start`,`react-build`に変更した上で、Electron用のスクリプトを追加しています。

```js:package.json
{
  ...
  "scripts": {
    // Electron のビルドスクリプト
    "electron-dev": "set ELECTRON_START_URL=http://localhost:3000 && electron public",
    "electron-build": "electron-packager build --platform=all --overwrite --asar",

    // React のビルドスクリプト
    "react-start": "react-scripts start", // 元の "start" から変更
    "react-build": "react-scripts build", // 元の "build" から変更

    // 開発時に使用
    "start": "concurrently \"npm run react-start\" \"npm run electron-dev\"",

    // ビルド時に使用
    "build": "npm run react-build && npm run electron-build"
  },
  // Reactのビルド時にリソースを相対パスで読み込むようにする
  "homepage": "./",
  "devDependencies": {
    ...
  }
}
```

`electron-dev`は環境変数`ELECTRON_START_URL`を設定した上で`electron public`を実行します。`electron-build`はElectronのスタンドアロン実行ファイルを作るコマンドです。詳しくは[electron-packager](https://github.com/electron-userland/electron-packager#from-the-command-line)の使い方を調べてください。

`"homepage": "./"`を指定することでReactのビルド時にソースの読み込み先が相対パスになります。これを付けておかないと最終的にビルドされたElectronアプリでのリソース読み込みがうまくいかなくなってしまいます。


## Electron実行用のファイルを追加

publicディレクトリ内に以下の二つのファイルを追加します。

```json:public/package.json
{
  "name": "helloworld",
  "version": "1.0.0",
  "main": "main.js"
}
```

```js:public/main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
const url = require('url')

let mainWindow

function createWindow() {
  mainWindow = new BrowserWindow({ width: 800, height: 600 })

  // 環境変数 ELECTRON_START_URL が定義されていればそれを使う。なければ index.html を使う。
  const startUrl = process.env.ELECTRON_START_URL || url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  })
  mainWindow.loadURL(startUrl)

  // 開発中のみ開発者ツールを表示
  if (process.env.ELECTRON_START_URL) {
    mainWindow.webContents.openDevTools()
  }

  mainWindow.on('closed', _ => {
    mainWindow = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', _ => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', _ => {
  if (mainWindow === null) {
    createWindow()
  }
})
```

main.jsは[electron-quick-startのmain.js](https://github.com/electron/electron-quick-start/blob/master/main.js)をちょっといじったものですが、`BrowserWindow`に読み込むURLを設定する箇所で環境変数`ELECTRON_START_URL`を見て、開発時とビルド時で読み込むURLを分けるようにしています。それ以外は通常のmain.jsと変わりません。

## 実行

ここまでできたら、Electronでアプリを実行してみましょう。

```
npm start
```

ローカルサーバーが立ち上がり、ブラウザでページを開くと同時にElectronが起動して同じページを表示します。この状態で`src/App.js`などを編集すると、自動的に再コンパイルが走って変更が反映されます。

## ビルド

コードが書けたら配布するためのファイルを作ります。

```
npm build
```

プロジェクトのディレクトリ以下に`helloworld-win32-x64`などができます。これを配布すれば開発環境のない別のマシンでも実行できます。