かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

React + TypeScript import 順をキレイにしたい

React のプロジェクトで import の並び順を揃えて見通しを良くしたい

前提

create-react-app --template typescript で作成したプロジェクトに ESLint と Prettier を導入してある

  • "react-scripts": "^5.0.0"
  • "react": "^17.0.2"
  • "typescript": "~4.1.5"
  • "eslint": "^8.6.0"
  • "prettier": "2.5.1"

1. 使用してない import 自動削除する

eslint-plugin-unused-imports を使用する

$ npm i -D eslint-plugin-unused-imports

.eslintrc.json に設定を追加する

{
  "plugins": [
    "react",
    "@typescript-eslint",
+   "unused-imports"
  ],
  "rules": {
+   "@typescript-eslint/no-unused-vars": "off", // or "no-unused-vars"
+   "unused-imports/no-unused-imports": "error",
+   "unused-imports/no-unused-vars": [
+     "warn",
+     { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" }
+   ],
  }
}
  • "@typescript-eslint/no-unused-vars" … unused-imports のルールとバッティングするので off にする
  • "unused-imports/no-unused-imports" … unused-imports の使用していない import に対するルール
  • "unused-imports/no-unused-vars" … unused-imports の no-unused-vars ルール
    • "vars": "all" … global スコープを含め全ての変数をチェックする
    • "varsIgnorePattern": "^_", … チェックしない変数を Regexp で指定できる。 _ で始まる変数が使用されてなくても OK にする
    • "args": "after-used" … 引数の使用してない変数に対するチェック。使用している変数が引数の最後の変数であれば、それより前の引数は使ってなくても OK
    • "argsIgnorePattern": "^_" … varsIgnorePattern の引数版。チェックしない引数を Regexp で指定できる。_ から始まる引数は使用のチェックを行わない

cf. no-unused-vars - Rules - ESLint - Pluggable JavaScript linter

2. import の並び順を揃える

eslint-plugin-import で import の順番を強制できる

$ npm i -D eslint-plugin-import

.eslintrc.json に設定を追加

{
  "plugins": [
    "react",
    "@typescript-eslint",
    "unused-imports",
+   "import"
  ],
  "rules": {
    // … 略
+   "import/order": []
  }
}

import の並び順のルール

.eslintrc.jsonimport/order ルール内に import の並び順のルールを記述する
GitHub にあるルールのドキュメント が参考になる

e.g.

{
  "rules": {
    "import/order": [
      "error",
      {
        // グループごとの並び順
        "groups": [
          "builtin",  // 1. fsや path などの node "builtin" のモジュール 
          "external",  // 2. npm install したパッケージ
          "internal", // 3. webpack などでパス設定したモジュール
          ["parent", "sibling"], // 4. 親階層と小階層のファイル
          "object",  // object"-imports
          "type",  // 型だけをインポートする type imports
          "index" // 同階層のファイル
        ],
        // グループごとに改行を入れる
        "newlines-between": "always", // "never" を指定すると改行なし
        // FIXME: ちょっとよく分かってない
        // This defines import types that are not handled by configured pathGroups. This is mostly needed when you want to handle path groups that look like external imports.
        "pathGroupsExcludedImportTypes": ["builtin"],
        // アルファベット順・大文字小文字を区別しない
        "alphabetize": { "order": "asc", "caseInsensitive": true },
        // パターンマッチしたものをグループにする
        // "newlines-between": "always" の場合は pathGroups  ごとに空行が入る
        "pathGroups": [
          // react 関連を external より前にする
          // "pathGroupsExcludedImportTypes": ["react"], にしてみたが `react`, `react-dom` などが別グループになってしまったので pattern で無理やり同じグループにした
          {
            "pattern": "react**",
            "group": "external",
            "position": "before"
          },
          // `@/app`, `@/features/`, `@/libs` の import をひとグループにして internal の前に
          {
            "pattern": "{@/app/**,@/features/**,@/libs/**}",
            "group": "internal",
            "position": "before"
          },
          // `@/components`, `@/pages` の import をグルーピング
          {
            "pattern": "{@/components/**,@/pages/**}",
            "group": "internal",
            "position": "before"
          },
          // CSS module を一番最後に
          {
            "pattern": "./**.module.css",
            "group": "index",
            "position": "after"
          }
        ]
      }
    ]
  }
}

ESLint でフォーマットするスクリプトを追加

未使用の import の削除も import の順番の強制も ESLint のルールなので eslint --fix で修正できる
コードフォーマットの prettier 合わせてフォーマットできるように npm-script を作成しておくと便利

package-json

{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
+   "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
+   "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
+   "format": "npm run lint:fix && prettier --write 'src/**/*.{js,jsx,ts,tsx}'",
    "eject": "react-scripts eject"
  }

👇 フォーマット

$ npm run format

ESLint が実行された後に prettier でフォーマットされていれば OK

VS Code の保存時にフォーマットする

コマンド叩き忘れがないように保存時に自動フォーマットするようにしておく

.vscode/settings.json

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
}

おわり

ESLint 関連のルール ドキュメントの説明を見てもよくわからんのが結構あるので英語力…ってなる。
個人的にはどうなるのかのサンプルコードを載せていたほうが親切だよなって感じたので、自分がなにか公開する際はそうしようって思いました。

ESLint + Prettier の設定毎回毎回何度も作ってる気がするので、そろそろテンプレート化しておきたい。(作る度にパッケージのアップデートで指定方法が変わってたりするから毎回手直しすることにになってるけど…)


[参考]

Docker Postgres DB コンテナが起動しないにハマる

Django の docker 環境をクイックスタートのドキュメントを参考に作っていたけど DB にしていされていた Postgres のコンテナが起動しなかった。

docker-compose.yml

version: '3'
services:
  # 略
  db:
    image: postgres
    restart: always
    # 永続化
    volumes:
      - ./db/pgsql-data:/var/lib/pgsql

Postgres が起動しない

$ docker-compose up
db_1   | Error: Database is uninitialized and superuser password is not specified.
db_1   |        You must specify POSTGRES_PASSWORD to a non-empty value for the
db_1   |        superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
db_1   | 
db_1   |        You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
db_1   |        connections without a password. This is *not* recommended.
db_1   | 
db_1   |        See PostgreSQL documentation about "trust":
db_1   |        https://www.postgresql.org/docs/current/auth-trust.html

Postgres コンテナの起動にはパスワードの設定が必要になっていた

セキュリティ強化の一環でパスワードの設定が必須になっていたようです。

version: '3'
services:
  db:
    image: postgres
    restart: always
    # 永続化
    volumes:
      - ./db/pgsql-data:/var/lib/pgsql
+   environment:
+     POSTGRES_PASSWORD: password

POSTGRES_HOST_AUTH_METHOD=trust を設定すれば以前の通りパスワードなしでも使用できる

If you know that you want to be insecure (i.e. any one can connect without a password from anywhere), then POSTGRES_HOST_AUTH_METHOD=trust is how you opt in to that.

We really recommend setting a password and it was really a bad decision by me in the beginning to continue to allow running the database without a password (#31 (comment) & #36)
cf. Behaviour change between 9.5.20 and 9.5.21? · Issue #681 · docker-library/postgres · GitHub

version: '3'
services:
  db:
    image: postgres
    restart: always
    # 永続化
    volumes:
      - ./db/pgsql-data:/var/lib/pgsql
+   environment:
+     POSTGRES_HOST_AUTH_METHOD: trust

これでも OK っぽい。セキュリティの強化と言う意味ではパスワードを設定するほうが望ましそう。

所感

docker-compose のイメージはちゃんとバージョン指定しよう!

おわり


[参考]

brew pyenv から anyenv の pyenv に乗り換えたら python インストールでエラーになるようになった

brew pyenv を消して anyenv の pyenv で Python をインストールしようとしたら BUILD FAILED というエラーが出るようになってしまった…

環境

  • MacOS Big Sur (11.6.1)
  • anyenv 1.1.2
  • pyenv 2.2.3-1-g423de9ae

結論

  1. Xcode のバージョンが古かったので最新の v13.1 入れ直したらエラー pyenv 経由での Python がビルドできるようになった
  2. anyenv 内の pyenv 内の python が使われるようにするには .zshrceval "$(pyenv init --path)" が必要だった

brew pyenv から anyenv の pyenv に乗り換える

pyenv でインストールしたバージョンを削除

$ pyenv versions
$ pyenv uninstall <VERSION>

brew でインストールした pyenv を削除

$ brew uninstall pyenv

Users/USER_NAME/.pyenv フォルダを削除
.zshrc から brew pyenv へのパスを削除

- export PYENV_ROOT="$HOME/.pyenv"
- export PATH="$PYENV_ROOT/bin:$PATH"
- eval "$(pyenv init -)"

anyenv pyenv をインストール

$ anyenv install pyenv
Install pyenv succeeded!
Please reload your profile (exec $SHELL -l) or open a new session.

# シェルを再起動
$ exec $SHELL -l
# pyenv の確認
$ pyenv -v 
pyenv 2.2.3-1-g423de9ae

anyenv の pyenv でインストールしようとしたらビルドでエラーになる

$ pyenv install 3.10.1
python-build: use tcl-tk from homebrew
python-build: use readline from homebrew
python-build: use zlib from xcode sdk

BUILD FAILED (OS X 11.6.1 using python-build 2.2.3-1-g423de9ae)

なんらかの原因で python-build がコケてしまうっぽい。

X code をアップデートする

  1. Download and install the latest Xcode 12 beta
  2. Go to > Preferences > Locations > Command Line Tools > Choose Xcode 12.0.

cf. Unable to build Python on macOS Big Sur with Xcode 12 beta · Issue #1643 · pyenv/pyenv · GitHub

GitHub の issue にあったコメントには Xcode 12.0 と書かれてましたが現在の最新は 13.1 で、local に入っている Xcode は 11.5 でした。
Xcode (11.5) 経由で使っている zlib が怪しいっぽいので、手っ取り早く Xcode を v13.1 にアップデートします。

https://developer.apple.com/download/all/ から最新の X code をダウンロードする。(サイズでかい…)

# シェルを再起動
$ exec $SHELL -l
# pyenv でのインストールを再挑戦
$ pyenv install 3.10.1
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.10.1.tar.xz...
-> https://www.python.org/ftp/python/3.10.1/Python-3.10.1.tar.xz
Installing Python-3.10.1...
python-build: use tcl-tk from homebrew
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.10.1 to /Users/kikiki/.anyenv/envs/pyenv/versions/3.10.1

$ pyenv versions
* system (set by /Users/USER_NAME/.anyenv/envs/pyenv/version)
  3.10.1
$ pyenv global 3.10.1

₍ ᐢ. ̫ .ᐢ ₎ よし

pyenv global が効いてない

pyenv global で設定した Python が設定されていることを確認するために別途ターミナルを開いてみた所…

$ python --version
Python 2.7.16
$ pyenv versions
  system
* 3.10.1 (set by /Users/USER_NAME/.anyenv/envs/pyenv/version)
$ which python
/usr/bin/python

anyenv 内の pyenv ではなく local にデフォルトで入っていた Python が使われているようです…
なんでや工藤…

eval "$(pyenv init --path)" が必要だった

homebrew の時は eval "$(pyenv init -)" だったけど、anyenv の pyenv は eval "$(pyenv init --path)" が無いとダメっぽい
.zshrc に書きを追記します

# pyenv
eval "$(pyenv init --path)"
$ exec $SHELL -l
$ python --version
Python 3.10.1
$ which python
/Users/USER_NAME/.anyenv/envs/pyenv/shims/python

₍ ᐢ. ̫ .ᐢ ₎ 今度こそよし!!!

所感

教訓。
年末年始の忙しい時にスナック感覚で折角だから〜と環境大掃除しようとすると死ぬ。


[参考]