React Hooks (TypeScript) + Firebase web 読書感想Webアプリを作る(その1. 環境構築編)

## 作ったもの

読書感想を本の表紙に帯を重ねた画像にしてSNSかLINEにシェアできるアプリを作成します。

hostingは Firebase 使います。認証もできたら追加したい。

## 構成

- typescript
- React (Hooks)
- repository : https://github.com/ryosuketter/obi
- hosting : Firebase : https://obishare.web.app/

（進めていくうちに更新の可能性あり）

## 環境

## React App Project の作成

create react-appで雛形を作成。

```
$ yarn create react-app obi --template typescript
```

必要なパッケージをインストール。

```
$ cd obi
$ yarn add typescript @types/node @types/react @types/react-dom @types/jest
$ yarn add firebase @types/firebase
```

以下コマンドを打つと、ブラウザが起動しサンプルのページが表示される。

```
$ yarn start
```

![スクリーンショット 2020-12-20 0.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/1b5a879c-e2c7-dcfd-285d-ef60f2819fb3.png)


これでローカル上で、React + TypeScriptの環境ができた。

## Firebaseのセットアップ

https://console.firebase.google.com/

FirebaseのConsoleで新しいProjectの作成します。

![スクリーンショット 2020-12-20 1.11.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/7c977d4a-4ffb-2c87-2d0a-ffe7e266416a.png)

Google アナリティクス は一応有効にする。

settingsの下の方にiOSかAndroidかWeb（`</>`）のボタンがあるのでWebのボタンをクリックします。

![スクリーンショット 2020-12-19 14.57.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/c97a9953-7a37-ff9c-0a19-d006226527a8.png)

### Firebase CLI のインストール

Firebase Hosting を使用してサイトをホストするには、Firebase CLI（コマンドライン ツール）が必要です。

次の npm コマンドを実行して、CLI をインストールするか、最新バージョンの CLI に更新します。

```bash
npm install -g firebase-tools
```

Google へのログイン

```
firebase login
```

参考

[Firebaseでデプロイしよう！ \- Qiita](https://qiita.com/hiroki-harada/items/ca22ac177db68e3c3796#03-firebase%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8D%E3%81%86)

## ローカルで Firebase init して、Firebaseと紐付ける

```
$ firebase init
```

ホスティング（Firebase Hostingサイトの設定と展開）にだけしかチェックしていません。

```
? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your
choices.
 ◯ Database: Configure Firebase Realtime Database and deploy rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
 ◉ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
 ◯ Emulators: Set up local emulators for Firebase features
 ◯ Remote Config: Get, deploy, and rollback configurations for Remote Config
```

Setup の Log は以下です。

```
=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? No
? Set up automatic builds and deploys with GitHub? Yes
✔  Wrote public/404.html
? File public/index.html already exists. Overwrite? No
i  Skipping write of public/index.html

i  Detected a .git folder at /Users/ryosuke/Project/obi
i  Authorizing with GitHub to upload your service account to a GitHub repository's secrets store.

Waiting for authentication...

✔  Success! Logged into GitHub as ryosuketter

? For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository) ryosuketter/obi

✔  Created service account github-action-322889681 with Firebase Hosting admin permissions.
✔  Uploaded service account JSON to GitHub as secret FIREBASE_SERVICE_ACCOUNT_OBISHARE.
i  You can manage your secrets at https://github.com/ryosuketter/obi/settings/secrets.

? Set up the workflow to run a build script before every deploy? Yes
? What script should be run before every deploy?

✔  Created workflow file /Users/ryosuke/Project/obi/.github/workflows/firebase-hosting-pull-request.yml
? Set up automatic deployment to your site's live channel when a PR is merged? Yes
? What is the name of the GitHub branch associated with your site's live channel? main

✔  Created workflow file /Users/ryosuke/Project/obi/.github/workflows/firebase-hosting-merge.yml

i  Action required: Visit this URL to revoke authorization for the Firebase CLI GitHub OAuth App:
https://github.com/settings/connections/applications/89cf50f02ac6aaed3484
i  Action required: Push any new workflow file(s) to your repo

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

✔  Firebase initialization complete!
```

### Deployする

```
$ firebase deploy
```

そして、いざホスティングしても公開URL (https://myobi-b92f8.web.app/) には、React App 初期画面が反映されていませんでした。

Publicディレクトリが対象になっているので、Reactのbulidディレクトリに変更します。

```json:myobi/firebase.json
{
  "hosting": {
    "public": "build", // public -> build
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}
```

そうすると、いつものReact の あの画面が反映されました。

![スクリーンショット 2020-12-20 0.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/22e3e96d-a9e3-f28a-5331-173bc6eaf8a4.png)

参考

[【React入門】Firebase Hostingに公開する方法 – デプロイ \| UX BEAR【ゆえっくま】](https://uxbear.me/firebase-deploy/#5_Firebase%E3%81%AB%E5%85%AC%E9%96%8B%EF%BC%88%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%EF%BC%89)

#### Deploy に関して

npm scriptにdeployスクリプトを追加することで

```bash
"scripts": {
    ...
    "deploy": "firebase deploy"
},
```

これで deploy できるようにする。

```bash
$ yarn deploy
```

そすれば、下記で、build と deploy できるようになるので。

```bash
$ yarn build
$ yarn deploy
```

そうすると、いつものReact の あの画面が

firebase にも反映されました。

https://obishare.web.app/

![スクリーンショット 2020-12-20 0.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/22e3e96d-a9e3-f28a-5331-173bc6eaf8a4.png)

参考

[Firebase公式のGitHubとHostingのインテグレーションが熱い🔥](https://zenn.dev/watarukun/articles/8f3e318bacf97cabf879)

## フロントエンド 開発環境設定

eslintの警告やエラーを無視したままコミットをしないように、できれば、

git add 〜
git commit 〜

の際にeslintによるチェックをかけて、commitできないようにします。

また、VSCode保存時にコード整形の設定もします。

- husky : gitコマンドをhookして、指定したコマンド（linterなりspecなり）を走られることができる
- lint-staged : ステージングしたファイルに対して特定のコマンドを実行できる
- prettier : コードフォーマッター（ソースコード を整形してくれるツール）
- eslint : 定めたコーディングルールに合わないことをすると即時エラーをだす
- eslint-config-prettier : 競合するeslintのルールを無効化することができる

インストールコマンド

```
$ yarn add -D husky lint-staged prettier eslint eslint-config-prettier
```

また、以下もインストールします。

```
$ yarn add -D @typescript-eslint/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/parser
```

### eslintの設定

```json:obi/.eslintrc.json
{
  // 適用する環境
  "env": {
    "es6": true,
    "node": true,
    "browser": true,
    "commonjs": true
  },
  // パーサー
  "parser": "@typescript-eslint/parser",
  // jsx を使います
  "parserOptions": {
    "ecmaVersion": 2018,
    "ecmaFeatures": {
      "jsx": true
    },
    "sourceType": "module"
  },
  // React のバージョンは自動検出に
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "plugins": ["react-hooks", "react", "@typescript-eslint"],
  // 基本的にルールは recommended に従う
  // prettier 関連は配列の最後尾に書く
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "prettier",
    "prettier/react",
    "prettier/@typescript-eslint"
  ],
  "rules": {
    // TypeScirpt なので prop-types は要らない
    "react/prop-types": "off"
  },
  // .js ファイルをオーバーライド （webpack.conig.jsなど）
  "overrides": [
    {
      "files": ["*.js"],
      "rules": {
        "@typescript-eslint/no-var-requires": "off",
        "@typescript-eslint/explicit-function-return-type": "off"
      }
    }
  ]
}
```

eslint が単体で動くかを検証。

```
$ yarn eslint . --ext .tsx --ext .ts


*******/obi/src/App.tsx
  5:1  warning  Missing return type on function  @typescript-eslint/explicit-module-boundary-types

*******/obi/src/reportWebVitals.ts
  3:25  warning  Missing return type on function  @typescript-eslint/explicit-module-boundary-types
```

2つ warningが出たけど、トリアヘズ気にしない。

参考

[VSCode \+ ESLint \+ Prettier \+ React \+ TypeScript （自分用メモ Fall, 2020） \- Qiita](https://qiita.com/sprout2000/items/ee4fc97f83f45ba1d227)

[create\-react\-app Lint構築よくばりパック\(ESLint \+ TypeScript \+ airbnb \+ Prettier \+ lint\-staged & husky \+ VSCode拡張\) \- Qiita](https://qiita.com/jonakp/items/7d9f47c613c16cbf95aa)

### prrettierの設定

```json:obi/.prettierrc.json
{
  "printWidth": 120,
  "singleQuote": true,
  "trailingComma": "none",
  "tabWidth": 2,
  "useTabs": true,
  "semi": false,
  "jsxSingleQuote": true,
  "arrowParens": "avoid",
  "bracketSpacing": true,
  "jsxBracketSameLine": true
}
```

- printWidth: 改行上限値
- singleQuote: " " → ' '
- trailingComma: 文末のコンマ ,
- tabWidth: タブサイズ
- useTabs: インデントにタブを使用
- Semi: セミコロンの有無
- jsxSingleQuote: jsxにおける " " → ' '
- arrowParens: allow関数での ( ) の有無
- bracketSpacing: {module} → { module }
- jsxBracketSameLine: <jsx>を複数行に分ける

参考

[\.prettierでコードを綺麗に \- GitPress\.io](https://gitpress.io/@fukke0906/20200927)

#### ファイル保存時にフォーマットをおこなう場合

VSCodeの.setting.jsonを編集します。

"editor.formatOnSave"をfalseに設定するとESLintのfixが対象でないファイルのフォーマットが行われません。

ESLintでfixを実行するファイルのみ"editor.formatOnSave"をfalseにします。

```json:settings.json
"editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  // Enable per-language basis by scoping for Prettier
  "[javascript]": {
    "editor.formatOnSave": true
  },
  "[javascriptreact]": {
    "editor.formatOnSave": true
  },
  "[typescriptreact]": {
    "editor.formatOnSave": true
  },
  "[typescript]": {
      "editor.formatOnSave": false
  }
```

これで、できてますね。

![91ab45a483f792023cd2c5e045b59ed6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/a702fb93-1754-fd8b-90d1-621827e8ebab.gif)

参考

[【VSCode】ESLint（fixあり/fixなし）とPrettierを保存時に走らせる \- Qiita](https://qiita.com/ebi113/items/50cd14b829e0f7bb08df#eslint%E3%81%AEfix%E3%82%92%E4%BF%9D%E5%AD%98%E6%99%82%E3%81%AB%E5%AE%9F%E8%A1%8C%E3%81%97fix%E3%81%A7%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E3%82%92%E3%81%8A%E3%81%93%E3%81%AA%E3%81%86%E5%A0%B4%E5%90%88)### huskyとlint-stagedの設定

### lint-staged と huskyの設定

```json:obi/.package.json
{
  "lint-staged": {
    "*.js": [
      "eslint --fix",
      "git add"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }
}
```

`"scripts": {...},`などと同階層に追加します。

試しに、git commit したら、ちゃんとチェックしてくれていました。

![スクリーンショット 2020-12-20 22.24.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/ccc1fc52-8f51-0b8a-95a0-795fd4b9d00f.png)

今回はこれで終わりです。