Electron + React + Redux + TypeScript でデスクトップアプリケーションを作るメモ

Electron + React + Redux + TypeScript でデスクトップアプリケーションを作ろう！というモチベーションで、`npm i`だけですぐ中身を作り始められるテンプレートがあったら便利だなと思ったので個人的メモ。
2019/03/01現在動作確認済みですが、今後バージョンアップで動かなくなったら内容更新したいと思います。



# 利用する技術
- Node.js ... サーバーサイドJavaScript
- npm ... Node.jsのパッケージを管理するツール(= Node Package Manager)
- Electron ... デスクトップアプリをWeb技術で開発できるフレームワーク
- React ... UI構築ライブラリ
- Redux ... state（状態）管理フレームワーク
- TypeScript ... JavaScriptと互換性があり、静的型付けやクラス設計が可能なプログラミング言語
- webpack ... JavaScriptモジュールバンドラ



# 前提条件
Node.jsがPCにインストールされていること


# 構成
package.json ... npmライブラリの依存関係を記述
tsconfig.json ... TypeScriptのコンパイルオプションを定義
tslint.json ... コンパイラが行う構文チェックのルールを設定
webpack.config.js ... webpackのビルド設定
main.js ... Electronのメインプロセス
index.html ... UIとなるHTML
ts/index.tsx ... React Component
ts/components/FoundationStyles.ts ... 共通スタイル設定
.gitignore ... Gitリポジトリで無視するファイルを設定



# 各ファイルの初期内容

### package.json

``` package.json
{
  "name": "electron-react-sample-app",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "electron ./"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "clone": "^2.1.2",
    "react": "^16.8.3",
    "react-dom": "^16.8.3",
    "react-redux": "^6.0.1",
    "redux": "^4.0.1",
    "reset-css": "^4.0.1",
    "styled-components": "^4.1.3",
    "uuid": "^3.3.2"
  },
  "devDependencies": {
    "@types/clone": "^0.1.30",
    "@types/react": "^16.8.6",
    "@types/react-dom": "^16.8.2",
    "@types/react-redux": "^7.0.1",
    "@types/redux": "^3.6.0",
    "@types/styled-components": "^4.1.11",
    "@types/uuid": "^3.4.4",
    "css-loader": "^2.1.0",
    "electron": "^4.0.6",
    "style-loader": "^0.23.1",
    "ts-loader": "^5.3.3",
    "tslint": "^5.13.0",
    "tslint-loader": "^3.5.4",
    "typescript": "^3.3.3333",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  }
}
```

### tsconfig.json

``` tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "jsx": "react",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true,
    "sourceRoot": "./tsx",
    "inlineSourceMap": true,
    "inlineSources": true
  },
  "include": [
    "./ts/**/*"
  ]
}
```

### tslint.json

``` tslint.json
{
    "defaultSeverity": "error",
    "extends": [
        "tslint:recommended"
    ],
    "jsRules": {},
    "rules": {
        // ここにルールを追加
    },
    "rulesDirectory": []
}
```

### webpack.config.js

``` webpack.config.js
const path = require('path');

module.exports = {
    target: 'node',
    entry: './ts/index.tsx',
    cache: true,
    mode: 'development',
    devtool: 'source-map',
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'index.js'
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader'
            },
            {
                test: /\.tsx?$/,
                enforce: 'pre',
                loader: 'tslint-loader',
                options: {
                    configFile: './tslint.json',
                    typeCheck: true,
                },
            },
            {
                test: /\.css$/,
                loaders: ['style-loader', 'css-loader'],
            }
        ],
    },
    resolve: {
        extensions: [
            '.ts',
            '.tsx',
            '.js',
        ]
    },
};
```

### main.js

``` main.js
const { app, BrowserWindow } = require('electron');

let win;

function createWindow() {
    win = new BrowserWindow({
        width: 800,
        height: 600
    })
    win.loadFile('index.html')
    if (process.argv.find((arg) => arg === '--debug')) {
        win.webContents.openDevTools()
    }
    win.on('closed', () => {
        win = null
    })
}

app.on('ready', createWindow)

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

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

### index.html

``` index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sample App</title>
</head>
<body>
    <div id="contents"></div>
    <script src="dist/index.js"></script>
</body>
</html>
```

### ts/index.tsx

``` index.tsx
import React from 'react';
import ReactDom from 'react-dom';

const container = document.getElementById('contents');

ReactDom.render(
    <p>Hello, World!</p>,
    container,
);
```

### ts/components/FoundationStyles.ts

``` FoundationStyles.ts
import 'reset-css/reset.css';

import { createGlobalStyle } from 'styled-components';

// グローバル スタイル 定義
// tslint:disable-next-line:no-unused-expression
export const GlobalStyle = createGlobalStyle`
    html, body {
        font-family: "Meiryo UI";
        font-size: 12pt;
        height: 100%;
        width: 100%;
    }
`;
```

### .gitignore

```
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/build
/dist

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.idea
```


# node modules(必須)

### npm install --save
- react
- react-dom
- redux
- react-redux

### npm install --save-dev （型定義ファイル含む）
- @types/react
- @types/react-dom
- @types/redux
- @types/react-redux
- electron
- typescript
- tslint
- webpack
- webpack-cli
- ts-loader
- tslint-loader
- style-loader
- css-loader



# node modules(任意)
### npm install --save
- styled-components ... CSS in JavaScriptのためのライブラリ
- reset-css ... ブラウザのデフォルトスタイルのリセットと共通スタイルの定義
- uuid ... 一意のIDを生成
- clone ... オブジェクトの複製を生成

### npm install --save-dev （型定義ファイル含む）
- @types/styled-components
- @types/uuid
- @types/clone


# 今回のGitリポジトリ

ダウンロードして
`$ npm i`
`$ npm run build`
`$ npm start`
でElectronでHello, world!が立ち上がるはず。
これで環境構築2~3分ですぐ中身作り始められる〜スッキリ！

https://github.com/aimy-07/electlon-react-sample-app



# 参考サイト

めっちゃわかりやすかった！！素晴らしや！
https://qiita.com/EBIHARA_kenji/items/25e59f7132b96cb886f3


# おわりに
今回は以上です。
当方Web開発初学者のため、間違い等ありましたらご指摘お願いいたします。
ありがとうございました。