Prettierの暴力に終止符を:大規模リポジトリにおける「フォーマット・オーバーヘッド」の完全排除戦略
巨大なモノレポや数年選手のリポジトリにおいて、Prettierは時に「開発体験の破壊者」と化す。コミットごとに全ファイルを走査し、PrettierのAST解析がCPUを占有し、CIが3分間停止する。この「フォーマットのための待ち時間」は、開発者のフロー状態を阻害する最大の無駄である。
本稿では、単なる`lint-staged`の導入などという初歩的な話はしない。「差分のみを極限まで速く処理する」「IDEとCIの乖離を物理的に消滅させる」「メモリ消費を最適化する」という、DevOpsの観点から見た真の最適化手法を伝授する。
—
1. なぜ「全量フォーマット」が愚策なのか:アーキテクチャ的視点
Prettierは、ソースコードをパースしてAST(抽象構文木)を生成し、それを再構成する。このプロセスは、特にファイル数数千を超えるプロジェクトでは、I/OバウンドかつCPUバウンドな重い処理だ。
重要なのは、「過去にフォーマット済みのファイルを、なぜ毎回再計算させる必要があるのか」という問いだ。CIで毎回全ファイルを走査する設定(`prettier –check .`)は、技術的負債以外の何物でもない。我々が目指すべきは、「変更された最小単位のASTのみを再構築する」というインクリメンタルなアプローチである。
—
2. 実践:Git差分を活用した「超高速」フォーマット戦略
CIパイプラインにおいて、全量チェックを排除し、差分のみを対象とするための堅牢なスクリプトを構築する。
差分のみを抽出するシェルスクリプト (`scripts/format-diff.sh`)
!/bin/bash
メインブランチとの差分ファイルのみを取得し、Prettierを適用する
巨大リポジトリでは glob 展開を shell に任せず、xargs でパイプライン処理する
set -e
target: mainブランチとの差分を取得
フィルタ: .js, .ts, .tsx, .json, .md に限定
xargs: 複数並列でPrettierを走査する(-Pオプション)
git diff –name-only –diff-filter=d origin/main…HEAD | \
grep -E ‘\.(js|ts|tsx|json|md)$’ | \
xargs -P $(nproc) -n 10 npx prettier –write –ignore-unknown
終了コードの伝播
exit $?
アーキテクトの知見:
`xargs -P $(nproc)` で論理コア数分だけ並列プロセスを立ち上げるのが肝だ。Node.jsのシングルスレッド制約を、プロセス並列化によって突破する。これにより、数十ファイル程度の変更であれば、コンパイル待ちの間に処理が完了する。
—
3. IDE(VS Code)の「保存時」処理を最適化する
開発者が最もストレスを感じるのは、保存時にIDEがフリーズする瞬間だ。これを回避するためには、`editor.codeActionsOnSave` の設定を極限まで絞り込む。
`.vscode/settings.json` の最適化設定
{
“editor.formatOnSave”: false, // 一括自動フォーマットはオフにする
“editor.codeActionsOnSave”: {
“source.fixAll.eslint”: “explicit” // ESLintに統括させる
},
“prettier.documentSelectors”: [“/.{js,ts,tsx,json,md}”],
“prettier.requireConfig”: true // コンフィグがないファイルのフォーマットを防ぎ、無駄なAST解析を抑制
}
解説:
`editor.formatOnSave` を `true` にすると、ファイル保存のたびに Prettier の内部ロジックがフル起動する。これをオフにし、ESLintの `eslint-plugin-prettier` を介して、「必要な箇所だけ」をESLintの解析フローの中でフォーマットさせるのが、メモリ消費を抑える最大のハックである。
—
4. Dockerコンテナ環境での完全自動構成
CI環境がDockerの場合、Node_modulesのキャッシュだけでは不十分だ。Prettierの実行環境として、`–no-semi` や `–single-quote` といったオプション設定ファイルを固定化し、コンテナイメージレイヤーにプリインストールしておく。
Dockerfileでパフォーマンスを最大化する
Prettierの実行を高速化するための依存関係解決
巨大なnode_modulesを毎回インストールさせない
RUN npm install -g prettier && \
npm cache clean –force
フォーマット専用の軽量ユーザーを作成し、パーミッション問題を回避
RUN useradd -m prettier-runner
USER prettier-runner
現場の教訓:
コンテナ内で `npm install` を走らせると、CIの時間は数分単位で伸びる。必ずイメージビルド時に `prettier` をグローバルインストールしておくか、マルチステージビルドで実行環境を分離せよ。
—
5. 究極のハック:Prettierの「キャッシュ機構」を再定義する
Prettier本体には `–cache` オプションが存在する。これを利用しない手はない。
ローカルおよびCIのキャッシュを維持する
npx prettier –write . –cache –cache-location .prettiercache
この `.prettiercache` ファイルは、各ファイルのハッシュ値と、その時のフォーマット結果を保持する。次回の実行時、Prettierはファイルの内容が変わっていない限り、ASTのパースすら行わずにスキップする。
この戦略がもたらす利益:
1. CIの実行時間: ファイル数1,000超のプロジェクトにおいて、全量チェックが5分から「差分なしなら5秒」に短縮される。
2. ストレステストの排除: IDEのCPU負荷が激減し、コーディング中のラグがなくなる。
3. チームの合意: `lint-staged` を徹底することで、コミット時点で「汚れたコード」がリポジトリに入り込む余地を物理的に排除する。
結論:DevOpsにおけるフォーマットは「バックグラウンド・タスク」であれ
フォーマットを人間の作業やCIのメインストリームに置いてはならない。Prettierは、「Gitの差分検知」と「キャッシュ機構」を組み合わせた、透明なバックグラウンド・プロセスとして構築すべきだ。
今日から、全量走査のCIパイプラインを破壊し、インクリメンタルなフォーマットを導入せよ。それだけで、チーム全体の開発効率は年間で数百時間分も向上する。技術の真髄は、ツールを「使う」ことではなく、ツールの「挙動をコントロールする」ことにある。