📌

Prettierの設定を見ていくぞ!(Vite)

2022/09/24に公開

はじめに

Romeの比較検証をしたかったのですが、ikura1にはTypeScriptフォーマッタのことがわからない。
ということで、パッケージにある設定を読み解き理解しようという試みです。

https://github.com/vitejs/vite

除外ファイル(.prettierignore)

.gitignore
packages/*/CHANGELOG.md
playground-temp/
dist/
temp/
LICENSE.md
pnpm-lock.yaml
pnpm-workspace.yaml
playground/tsconfig-json-load-error/has-error/tsconfig.json
playground/html/invalid.html
playground/html/valid.html
playground/worker/classic-worker.js

除外されているのはおおまかに4種類

  • 文章(CHANGELOG.md, LICENSE.md)
    • CHANGELOG.mdやLICENSE.mdなど自動生成や変更する必要のない文章
  • 生成される・一時ファイル(dist, temp)
    • buildで生成されるコードや一時ファイル
  • テスト環境(playground)
  • pnpmのファイル

設定ファイル(.prettierrc.json)

.prettierrc.json
{
  "semi": false,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 80,
  "trailingComma": "none",
  "overrides": [
    {
      "files": ["*.json5"],
      "options": {
        "singleQuote": false,
        "quoteProps": "preserve"
      }
    },
    {
      "files": ["*.yml"],
      "options": {
        "singleQuote": false
      }
    }
  ]
}
  • "semi": false
    • セミコロンの設定
      • なし
  • "tabWidth": 2,
    • タブ幅の設定
      • 2
  • "singleQuote": true
    • クォートの設定
      • シングルクォート
  • "printWidth": 80
    • 1行の文字数制限
      • 80
  • "trailingComma": "none"
    • 末尾のカンマ設定
      • なし

上書き設定
拡張子ごとの上書き設定

  • *.json5
    • "singleQuote": false
      • ダブルクォート
    • quoteProps: "preserve"
      • オブジェクトの入力優先
  • *.yml
    • ダブルクォート

補足

quoteProps
https://prettier.io/docs/en/options.html#quote-props
オブジェクトのプロパティ名をクォートで囲むかの設定

// as-needed
const hoge = {
    hoge: 'hoge',
    'ho-ge': 'hige'
}
// consistent
const hoge = {
    'hoge': 'hoge',
    'ho-ge': 'hige'
}
// preserve
const hoge = {
    'hoge': 'hoge',
    hige: 'hige'
}
  • as-needed
    • 必要であるプロパティ名のみ囲みます
  • consistent
    • 一つでも必要なプロパティ名がある場合、全てを囲みます
  • preserve
    • 入力された状態を尊重します

trailingComma
https://prettier.io/docs/en/options.html#trailing-commas
複数行のカンマ区切り構文での末尾へのカンマ設定

// none
const hoge = [
    1,
    2
]

// all or es5
const hoge = [
    1,
    2,
]

上記の例ではes5noneは一行にまとめられてしまうため、正しい形ではありません。
ですが概ねそんな感じです。

  • es5
    • ES5で有効時に付ける
  • none
    • カンマを付けない
  • all
    • 可能な限り末尾にカンマを付ける

パッケージファイル(package.json)

package.json
{
  "scripts": {
    "preinstall": "npx only-allow pnpm",
    "postinstall": "simple-git-hooks",
    "format": "prettier --write --cache .",
    "lint": "eslint --cache .",
  },
  "simple-git-hooks": {
    "pre-commit": "pnpm exec lint-staged --concurrent false",
    "commit-msg": "pnpm exec tsx scripts/verifyCommit.ts $1"
  },
  "lint-staged": {
    "*": [
      "prettier --write --cache --ignore-unknown"
    ],
    "packages/*/{src,types}/**/*.ts": [
      "eslint --cache --fix"
    ],
    "packages/**/*.d.ts": [
      "eslint --cache --fix"
    ],
    "playground/**/__tests__/**/*.ts": [
      "eslint --cache --fix"
    ]
  }
}

lintformatに関係がある部分に削ったのが上記になります。

  • "format": "prettier --write --cache ."
    • prettierのフォーマットコマンド
  • "lint": "eslint --cache ."
    • eslintlintコマンド
  • "postinstall": "simple-git-hooks"
    • gitフックライブラリ
  • "preinstall": "npx only-allow pnpm"
    • pnpm以外使用させない設定

prettierのオプション補足

--cache
https://zenn.dev/sosukesuzuki/articles/1d1bfb73118a9b
https://prettier.io/docs/en/cli.html#--cache
下記の値がキャッシュキーとして使用されて、いずれかが変更されて場合のみファイルがフォーマットされます。

  • Prettier バージョン
  • Prettier オプション
  • Node.js バージョン
  • --cache-strategyの場合は
    • metadata
      • ファイルのメタデータ(タイムスタンプなど)
    • content
      • ファイル内容

--write
https://prettier.io/docs/en/cli.html#--write
フォーマットしたファイルを全て書き換えます。

--ignore-unknown
https://prettier.io/docs/en/cli.html#--ignore-unknown
パターンマッチした未知のファイルを無視します。
パーサーが不明の場合にエラーを防止する設定です。

simple-git-hooksの補足

https://github.com/toplenboren/simple-git-hooks
simple-git-hooksはGitフックを簡単に管理できるライブラリです。

{
  "scripts": {
    "postinstall": "simple-git-hooks",
  },
  "simple-git-hooks": {
    "pre-commit": "pnpm exec lint-staged --concurrent false",
    "commit-msg": "pnpm exec tsx scripts/verifyCommit.ts $1"
  }
}

"postinstall": "simple-git-hooks"
git hooksコマンドを更新する。
コマンドを変更した場合にnpx simple-git-hooksを手動で実行する必要があります。
そのためのコマンドがscriptsに登録されている形になってます。

simple-git-hooks
git hooksで実行されるコマンドを設定します。

  • pre-commitはコミット以前に実行されるコマンド
    • lint-staged --concurrent falseを実行しています
  • commit-msgはコミットメッセージに対して実行されるコマンド
    • Viteではコミットメッセージがフォーマットに沿って入力されているかを確認しています
    • scripts/verifyCommit.ts

lint-stagedの補足

https://github.com/okonet/lint-staged
lint-stagedはステージング

{
  "simple-git-hooks": {
    "pre-commit": "pnpm exec lint-staged --concurrent false",
  },
  "lint-staged": {
    "*": [
      "prettier --write --cache --ignore-unknown"
    ],
    "packages/*/{src,types}/**/*.ts": [
      "eslint --cache --fix"
    ],
    "packages/**/*.d.ts": [
      "eslint --cache --fix"
    ],
    "playground/**/__tests__/**/*.ts": [
      "eslint --cache --fix"
    ]
  }
}

--concurent
同時実行するタスク数、シリアルの場合はfalse(デフォルトではtrue)

  • true(デフォルト)
    • 可能な限り多くのタスクを並列に実行します
  • false
    • 全てのタスクを順に実行します
  • {number}
    • 実行するタスク数、1の場合はfalseと同じ動作になります

lint-stagedの設定

"lint-staged": {
    "*": [
      "prettier --write --cache --ignore-unknown"
    ],
    "packages/*/{src,types}/**/*.ts": [
      "eslint --cache --fix"
    ],
    "packages/**/*.d.ts": [
      "eslint --cache --fix"
    ],
    "playground/**/__tests__/**/*.ts": [
      "eslint --cache --fix"
    ]
  }

lint-stagedでは、glob-patternでプロパティを設定します。
プロパティ名に一致したファイルに対して、コマンドを実行する形になります。
複数合致する場合は複数のコマンドが実行されます。

Viteは全体にprettierを実行し、eslintは細かく設定されています。

その他補足

npx only-allow pnpm
https://pnpm.io/only-allow-pnpm

プロジェクトでpnpmを使用している場合、npm installyarnなどのパッケージマネージャーを使用できないようにする設定
間違えて、npm installyarnを実行すると、エラーが発生しインストールできません。

Github Actionsの設定(.github/workflows/ci.yml)

.github/workflow/ci.yml
name: CI

env:
  # 7 GiB by default on GitHub, setting to 6 GiB
  # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
  NODE_OPTIONS: --max-old-space-size=6144
  # install playwright binary manually (because pnpm only runs install script once)
  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
  # Vitest auto retry on flaky segfault
  VITEST_SEGFAULT_RETRY: 3

on:
  push:
    branches:
      - main
      - release/*
      - feat/*
      - fix/*
      - perf/*
      - v1
      - v2
  pull_request:
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
  cancel-in-progress: true

jobs:
  lint:
    timeout-minutes: 10
    runs-on: ubuntu-latest
    name: "Lint: node-16, ubuntu-latest"
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install pnpm
        uses: pnpm/action-setup@v2.2.2

      - name: Set node version to 16
        uses: actions/setup-node@v3
        with:
          node-version: 16
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      - name: Build
        run: pnpm run build

      - name: Lint
        run: pnpm run lint

      - name: Check formatting
        run: pnpm prettier --check .

      - name: Typecheck
        run: pnpm run typecheck

上記はLintの部分にci.ymlを削ったものになります。

concurrency
https://docs.github.com/ja/actions/using-jobs/using-concurrency
同じグループで使うジョブやワークフローを1度に1つだけにする設定です。

concurrency:
  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
  cancel-in-progress: true
  • group
    • グループの設定
  • cancel-in-progress
    • キューが入った場合に、実行中ジョブのキャンセル有効無効設定

ジョブの設定(jobs:lint)

jobs:
  lint:
    timeout-minutes: 10
    runs-on: ubuntu-latest
    name: "Lint: node-16, ubuntu-latest"
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install pnpm
        uses: pnpm/action-setup@v2.2.2

      - name: Set node version to 16
        uses: actions/setup-node@v3
        with:
          node-version: 16
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      - name: Build
        run: pnpm run build

      - name: Lint
        run: pnpm run lint

      - name: Check formatting
        run: pnpm prettier --check .

      - name: Typecheck
        run: pnpm run typecheck

stepでの実行内容

  1. actions/checkout@v3
    1. リポジトリのチェックアウト
  2. Install pnpm
    1. pnpmのインストール
  3. Set node version to 16
    1. Node.jsのバージョン設定
  4. Install deps
    1. pnpmでのパッケージインストール
  5. Build
    1. パッケージビルド
  6. Lint
    1. pnpmでのlint実行
  7. Check Formatting
    1. pnpmでのprettierでのフォーマットチェック
  8. Typecheck
    1. pnpmでの型チェック

最後に

TypeScriptの設定をあまり知りませんでしたが、package.json内に完結されていて良いですね。
また便利なライブラリが多いのも良い。
問題は今回触れていませんが、eslintの設定がややこしい…

Romeとの比較の前段階として少し理解が深まりました。

GitHubで編集を提案

Discussion