「Prettierは遅い」と嘆く前に。`.prettierignore`を武器にしたCI/CD最適化とアーキテクチャの極意
多くのエンジニアにとって、Prettierは「保存時にコードを綺麗にしてくれる便利なツール」で止まっている。しかし、大規模なモノレポや数百のマイクロサービスを抱える現場において、Prettierは時に「CI/CDのボトルネック」という牙を剥く。
なぜ、あなたのCIは終了まで数分かかるのか? なぜ、IDEはファイルを保存するたびに一瞬フリーズするのか? 答えはシンプルだ。「Prettierが本来触れるべきでない領域まで、律儀に解析しているから」である。
今日は、`.prettierignore`を単なる「除外リスト」から、ビルドパイプラインを劇的に加速させる「戦略的フィルタリングエンジン」へと昇華させるための技術論を伝授する。
—
1. なぜ「隠れた除外」がCI/CDの勝敗を分けるのか
Prettierはファイルを探索する際、デフォルトで多くのパスを走査する。特に恐ろしいのは、`.gitignore`を自動的に読み込む仕様だ。一見便利だが、プロジェクトが巨大化すると、Git管理下にあるがPrettier不要な巨大なバイナリデータ、生成コード、あるいは依存関係のサブセットまでが「探索対象」としてメモリ上に展開される。
アーキテクチャ的視点:メモリ消費と探索コスト
Prettierの内部エンジンはAST(抽象構文木)の解析を行う。数万行の自動生成コードや、肥大化した`dist`ディレクトリ、あるいは`package-lock.json`等の巨大なJSONを走査対象に含めると、Node.jsのヒープメモリは瞬く間に枯渇する。
「CIで一度だけ走るから良い」という甘えが、クラウドコンテナのCPUクレジットを浪費し、開発者の生産性を削ぐ。 ここで、`.prettierignore`を「インフラ」として再定義する必要がある。
—
2. `.prettierignore` を「戦術的フィルタ」として活用する
単に `dist/` を書くだけでは不十分だ。現場で最も効果を発揮する「除外の極意」を共有する。
— 1. 自動生成系:解析コストの回避 —
コンパイル出力や型定義生成ディレクトリは解析対象から完全除外
dist/
build/
.generated.ts
.schema.d.ts
— 2. 外部要因系:パフォーマンスの安定化 —
依存関係はロックファイルがあるため、解析の必要性はほぼゼロ
node_modules/
— 3. 秘伝のタレ:CI専用の最適化 —
Gitで管理されているが、フォーマットが不要なバイナリデータや圧縮ファイル
.png
.jpg
.woff2
.ico
— 4. 盲点:IDEのフリーズ対策 —
巨大なデータセットやダンプファイル
.log
data/dump/
なぜこれが必要か?
Prettierは、ignoreリストを「最初」に評価し、探索パスを枝刈り(Pruning)する。この枝刈りを適切に行うことで、ファイルシステムへのアクセス回数が指数関数的に減る。これは、IO待ちが激しいCIコンテナ環境において、実行時間を数十秒単位で短縮する効果がある。
—
3. CI/CDパイプラインとの高度な連携:差分フォーマット戦略
CIで全ファイルをフォーマットするのは愚策だ。大規模環境では「変更されたファイルのみ」を対象にフォーマットすべきだが、`prettier –write` は時として「意図しない変更」を生成する。
これを防ぐのが、`.prettierignore` と `git diff` を組み合わせた検証パイプラインである。
!/bin/bash
CI実行時の最適化スクリプト例
直前のコミットで変更されたJS/TSファイルだけを抽出
FILES=$(git diff –name-only –diff-filter=ACMRTUXB origin/main | grep -E ‘\.(js|ts|jsx|tsx|json|md)$’)
if [ -n “$FILES” ]; then
# 変更対象のみをフォーマットし、差分をチェック
# –check を使用して「フォーマット違反があるか」を確認するだけでCIを落とす
npx prettier –check $FILES
else
echo “対象ファイルなし。スキップ。”
fi
このアプローチにより、CIは数秒で終了する。Prettierの探索コストをゼロに近づけつつ、品質を担保する。これが現場レベルの「DevOps」だ。
—
4. プロフェッショナルへの提言:パフォーマンスを極限まで引き出す
さらに一歩進んだ最適化として、以下の知見を頭に叩き込んでおいてほしい。
① `ignore` の二重管理を廃止せよ
多くのプロジェクトで `.gitignore` と `.prettierignore` の内容が重複している。管理コストを下げ、CIのミスを防ぐため、`.prettierignore` は `.gitignore` を継承させる運用を推奨する。
② Docker環境でのメモリ最適化
DockerコンテナでPrettierを走らせる際、デフォルトのNode.jsメモリ制限(通常512MB〜1GB程度)に引っかかることがある。CI定義ファイル内で以下のように明示的にメモリを割り当てるのがプロの流儀だ。
CIのステップ定義例 (GitHub Actions)
- name: Run Prettier
run: node –max-old-space-size=4096 $(which prettier) –check .
# 4GBのメモリを確保し、大規模モノレポでもスワップ発生を防ぐ
③ ループを防ぐ:生成コードの扱い
生成コード(Swagger等から生成される型定義など)がPrettierのフォーマット対象になると、Prettierの出力がソースコードを書き換え、それがトリガーとなって再びビルドが走り、無限ループに陥ることがある。これを防ぐには、生成コードの先頭に必ず `/ prettier-ignore /` を埋め込むスクリプトを生成タスクに組み込むことだ。
—
結論
`.prettierignore` を記述することは、単なる設定作業ではない。それは、「何がコードの真実であり、何がノイズであるか」をアーキテクトが定義する行為である。
ツールを骨の髄まで掌握する者は、ツールの「隠れた仕様」を味方につけ、パイプラインの摩擦を極限まで取り除く。あなたのCIが遅いのは、Prettierが悪いのではない。あなたが「対象外」を明示してこなかったからだ。
今日から、`.prettierignore` を「プロジェクトのパフォーマンスを支配するコントローラー」として再設計せよ。それだけで、チームの開発体験は劇的に向上するはずだ。