Prettierでコードを美しく:Pragmaオプションの活用と代替案
Prettierは、コードの自動整形ツールです。--insert-pragma
オプション(または設定ファイルで insertPragma: true
)を使用すると、Prettierは整形したファイルの先頭に特別なコメント(プラグマコメント)を挿入します。
このプラグマコメントは通常、以下の形式をとります。
/** @prettier */
/** @format */
または、言語によっては次のような形式になることもあります。
- Vue: ``
- GraphQL:
# @prettier
- CSS/Less/SCSS:
/** @prettier */
- YAML:
# @format
- Markdown: ``
「Insert Pragma」の主な目的は、--require-pragma
オプションと連携して、特定のファイルのみをPrettierで整形対象とする仕組みを提供することです。
なぜこのオプションが必要なのか?
大規模な既存のコードベースにPrettierを導入する際、一気に全てのファイルを整形するのはリスクが伴う場合があります。例えば、以下のような問題が考えられます。
- Gitの履歴が汚れる: 大量のファイルが一度に整形されるため、Gitの履歴が読みにくくなります。
- レビューの困難さ: 膨大な変更が一度に発生するため、コードレビューが非常に難しくなります。
- 予期せぬ挙動: Prettierの整形によって、意図しないコードの変更や問題が発生する可能性もゼロではありません。
このような場合に、「Insert Pragma」と「Require Pragma」の組み合わせが役立ちます。
--require-pragma
との連携
--require-pragma
(またはrequirePragma: true
): このオプションを設定すると、Prettierはファイルの先頭に上記のプラグマコメントがない限り、そのファイルを整形しません。--insert-pragma
(またはinsertPragma: true
): このオプションは、Prettierがファイルを整形した際に、そのファイルの先頭にプラグマコメントを挿入します。
具体的なワークフロー
- まず、Prettierの設定で
requirePragma: true
を有効にします。これにより、既存のファイルは勝手に整形されなくなります。 - 開発者が新しいファイルを作成したり、既存のファイルを編集したりする際に、そのファイルに対して手動でPrettierを実行します(例:
prettier --write --insert-pragma path/to/file.js
)。 --insert-pragma
によって整形されたファイルの先頭にプラグマコメントが挿入されます。- 次にPrettierが実行される際には、そのプラグマコメントが存在するため、該当ファイルは整形対象となります。
このようにして、コードベース全体を一度に整形するのではなく、開発者が触れたファイルから徐々にPrettierの整形を適用していく「段階的な導入」が可能になります。
- これにより、大規模なプロジェクトでPrettierを段階的に導入し、既存のコードベースへの影響を最小限に抑えることができます。
- このオプションは、
--require-pragma
オプションと組み合わせて使用することで、プラグマコメントを持つファイルのみをPrettierで整形する仕組みを実現します。 - Insert Pragma は、Prettierが整形したファイルの先頭に
/** @format */
や `` のような特別なコメント(プラグマコメント)を挿入するオプションです。
「Insert Pragma」は、Prettierの導入を段階的に行う際に便利な機能ですが、その特性上、いくつか混乱しやすい点やエラーが発生する可能性があります。
エラー:Prettierが期待通りに動作しない(整形されない、または整形されすぎる)
これは、「Insert Pragma」と「Require Pragma」の組み合わせに関する誤解が原因で最もよく発生する問題です。
よくある誤解
- 「
--require-pragma
を有効にすると、--insert-pragma
なしで整形できる」と思っている。 - 「
--insert-pragma
を指定すれば、常にPrettierが実行される」と思っている。
原因とトラブルシューティング
--require-pragma
が有効になっていないか確認する。- もし有効になっていない場合、Prettierは全てのファイルを整形しようとします。
--insert-pragma
は単にプラグマコメントを挿入するだけで、整形動作自体には影響しません。 - もし「段階的な導入」を目的としているのであれば、
requirePragma: true
を設定に追加する必要があります。
- もし有効になっていない場合、Prettierは全てのファイルを整形しようとします。
--require-pragma
(またはrequirePragma: true
) が有効になっているか確認する。- もし有効になっている場合、ファイルにプラグマコメントがないと、Prettierは整形を行いません。
- この場合、整形したいファイルにプラグマコメントを挿入する必要があります。初めて整形する場合は、
--insert-pragma
オプションを付けてPrettierを実行してください。# 例:特定のファイルを整形し、プラグマコメントを挿入する prettier --write --insert-pragma src/index.js
- プロジェクト全体で段階的に導入したい場合は、
requirePragma: true
を設定した上で、手動で整形したいファイルに対してprettier --write --insert-pragma
を実行します。
エラー:プラグマコメントが意図しない場所(または意図しない形式)に挿入される
原因とトラブルシューティング
- 他のツールやLinterとの競合。
- 一部のLinterや静的解析ツールが、ファイルの先頭にあるコメントについて特定のルールを持っている場合があります。
- この場合、Linterの設定を調整して、Prettierが挿入するプラグマコメントを無視するように設定する必要があるかもしれません。
- 特定のファイル形式のコメントルールを確認する。
- 例えば、JavaScriptやTypeScriptでは
/** @format */
や/** @prettier */
となりますが、Markdownでは ``、YAMLでは# @format
となります。Prettierはファイルの拡張子に基づいて適切なコメント形式を自動的に選択します。 - もしコメント形式が不適切だと感じた場合、それはPrettierがファイルの種類を正しく認識していない可能性があります。ファイル拡張子が正しいか、Prettierがその言語をサポートしているか確認してください。
- 例えば、JavaScriptやTypeScriptでは
- ファイルの先頭に挿入されるのは通常の動作です。 Prettierは、ファイルの先頭にプラグマコメントを挿入するよう設計されています。これは、Prettierがファイル全体を解析する前にその情報を読み取る必要があるためです。
エラー:CI/CDパイプラインでPrettierが失敗する
これは、CI/CD環境でのPrettierの実行方法と requirePragma
の設定が原因で発生します。
原因とトラブルシューティング
- CI環境のPrettierバージョンがローカルと異なる。
- Prettierのバージョンが異なると、整形結果やオプションの挙動に違いが出ることがあります。
package.json
で指定されたバージョンがCIで正しくインストールされているか確認してください。
- Prettierのバージョンが異なると、整形結果やオプションの挙動に違いが出ることがあります。
--insert-pragma
は--write
と共に使うオプションです。- CI/CDでコードを「整形してコミットする」ようなパイプラインを組んでいる場合を除き、通常CIでは
--insert-pragma
は使用しません。CIでは整形が必要なファイルの有無をチェックするだけが一般的です。 - もしCIで
prettier --write --insert-pragma
を実行すると、変更が発生し、CIが失敗する可能性があります(未コミットの変更として)。
- CI/CDでコードを「整形してコミットする」ようなパイプラインを組んでいる場合を除き、通常CIでは
- CI/CD環境では通常、
--check
オプションを使用します。prettier --check
は、コードがPrettierのルールに沿っているかをチェックし、整形が必要なファイルがあればエラーで終了します。- もし
requirePragma: true
が設定されているプロジェクトで、CI/CD環境でprettier --check
を実行している場合、プラグマコメントがないファイルはチェックされません。これは意図した動作かもしれませんが、もし全てのファイルをチェックしたい場合は、requirePragma: false
に変更するか、CIのステップで一時的に上書きする必要があります。
これはエラーというよりは、段階的な導入の副作用です。
- 対策
- これを避けるには、初期導入時に一度だけ
prettier --write
で全てのファイルを整形し、そのコミットを他の変更から分離する(例:git commit -m "feat: Apply Prettier formatting"
のような独立したコミットにする)。これにより、その後の変更は整形後のコードベースに対して行われるため、履歴がクリーンになります。 - しかし、これが困難な既存のプロジェクトでは、
--insert-pragma
による段階的な導入が現実的です。その場合、初回の整形コミットを理解し、レビュー時にはその整形による変更部分を意識して確認する必要があります。
- これを避けるには、初期導入時に一度だけ
--insert-pragma
を使用して少しずつファイルを整形していくと、各ファイルの初回の整形時に大きな変更がGitの履歴に残ります。
「Insert Pragma」は、主にコマンドラインインターフェース(CLI)や設定ファイルを通じて設定します。
ファイルの整形時にプラグマコメントを挿入する (--insert-pragma)
これは、特定のファイルを初めてPrettierで整形する際に使われる最も一般的な方法です。
src/my-module.js (整形前)
function myFunction( arg1, arg2 ) {
console.log( "Hello, world!" );
return arg1 + arg2;
}
const myVariable = 10;
コマンドラインでの実行
# --write: 整形結果をファイルに書き込む
# --insert-pragma: 整形後にプラグマコメントを挿入する
prettier --write --insert-pragma src/my-module.js
src/my-module.js (整形後)
/** @format */
function myFunction(arg1, arg2) {
console.log("Hello, world!");
return arg1 + arg2;
}
const myVariable = 10;
ご覧のように、ファイルの先頭に /** @format */
というプラグマコメントが挿入されました。
プラグマコメントがないファイルを整形しない (--require-pragma)
このオプションは、--insert-pragma
と組み合わせて使うことで、Prettierの段階的な導入を可能にします。
.prettierrc.json (設定ファイル)
{
"requirePragma": true
}
src/another-module.js (整形前、プラグマコメントなし)
function anotherFunction( a, b) {
return a * b;
}
src/yet-another-module.js (整形前、プラグマコメントあり)
/** @format */
function yetAnotherFunction( x, y) {
return x / y;
}
コマンドラインでの実行(requirePragma: true の設定がある場合)
# プロジェクト内の全てのJSファイルを整形しようとする
prettier --write "src/**/*.js"
結果
src/yet-another-module.js
は整形されます。- このファイルにはプラグマコメントがあるため、
requirePragma
の条件を満たし、整形が実行されます。整形後もプラグマコメントは維持されます。
- このファイルにはプラグマコメントがあるため、
src/another-module.js
は整形されません。- なぜなら、
.prettierrc.json
でrequirePragma: true
が設定されており、このファイルにはプラグマコメントがないためです。
- なぜなら、
--require-pragma を有効にしつつ、新しいファイルにプラグマを挿入して整形する
上記2つのオプションを組み合わせることで、開発者が新しいファイルを作成したり、既存のファイルを触ったりする際に、そのファイルだけをPrettierの管理下に置くことができます。
シナリオ
新しいファイル src/new-feature.js
を作成し、Prettierで整形したい。
src/new-feature.js (作成直後)
function implementNewFeature( data) {
console.log( "Processing", data );
}
コマンドラインでの実行
# このファイルだけを整形し、同時にプラグマコメントを挿入する
prettier --write --insert-pragma src/new-feature.js
src/new-feature.js (整形後)
/** @format */
function implementNewFeature(data) {
console.log("Processing", data);
}
これで、src/new-feature.js
は整形され、プラグマコメントが挿入されたため、以降 prettier --write "src/**/*.js"
のように全体を対象とするコマンドを実行した場合でも、このファイルは整形対象となります。
package.json に設定を追加する例
CLIオプションだけでなく、package.json
の prettier
キーや.prettierrc
ファイルで insertPragma
や requirePragma
を設定することもできます。
package.json
{
"name": "my-project",
"version": "1.0.0",
"prettier": {
"requirePragma": true,
"insertPragma": false, // 通常、insertPragmaはCLIで一時的に使うため、falseのままが多い
"semi": true,
"singleQuote": true
},
"scripts": {
"format": "prettier --write \"src/**/*.js\""
}
}
この設定の場合
- もし新しいファイルや既存のファイルにプラグマコメントを挿入したい場合は、別途
prettier --write --insert-pragma path/to/file.js
のように手動でコマンドを実行する必要があります。 - ただし、
requirePragma: true
なので、プラグマコメントが既に入っているファイルのみが整形されます。 npm run format
を実行すると、src
ディレクトリ以下の全ての.js
ファイルが整形対象となります。
.prettierrc.js で設定する例
JavaScriptファイルとして設定することも可能です。
/** @type {import("prettier").Config} */
const config = {
requirePragma: true,
// insertPragma: false, // CLIでコントロールすることが多いため、通常は設定しないかfalse
semi: false, // セミコロンなし
singleQuote: true, // シングルクォートを使用
};
module.exports = config;
「Insert Pragma」と「Require Pragma」の組み合わせは、既存の大規模なコードベースにPrettierを「徐々に」適用したい場合に非常に有効です。しかし、プロジェクトの性質やチームのワークフローによっては、以下の代替方法の方が適している場合もあります。
全てのファイルを一度に整形する (一括適用)
これは最もシンプルで直接的な方法であり、小規模なプロジェクトや、Prettierを導入する際にコードベース全体に大きな変更を加えることを許容できる場合に最適です。
方法
.prettierrc
ファイルでrequirePragma
を設定しない(またはfalse
にする)。- Prettierのデフォルト設定では、
requirePragma
はfalse
です。
- Prettierのデフォルト設定では、
- 一度だけ全てのファイルを整形するコマンドを実行する。
# プロジェクトのルートディレクトリで実行 prettier --write . # または特定のディレクトリを指定 prettier --write "src/**/*.{js,jsx,ts,tsx,json,css,md}"
- 整形結果を一つの大きなコミットとしてGitにプッシュする。
- 例:
git commit -m "feat: Apply Prettier formatting to entire codebase"
- 例:
利点
- 今後の変更は、既に整形されたコードベースに対して行われるため、Gitの履歴がクリーンに保たれる。
- コードベース全体が一度に統一されたスタイルになる。
- 設定がシンプル。
欠点
- 予期せぬ整形による問題が発生した場合、原因特定が困難になることがある。
- 初期コミットが非常に大きくなり、レビューや履歴の追跡が難しくなる可能性がある。
新規ファイルのみPrettierの管理下に置く (新規導入のみ)
既存のコードはそのままにし、これから作成する新しいファイルやモジュールのみをPrettierで整形したい場合に有用です。
方法
.prettierignore
を活用する。- Prettierの整形から除外したい既存のディレクトリやファイルを
.prettierignore
に記述します。 - 例えば、全ての既存のコードが含まれるディレクトリを無視するように設定し、新しいコードが作成されるディレクトリだけを対象にする。
# .prettierignore の例 legacy-code/ old-components/
- Prettierの整形から除外したい既存のディレクトリやファイルを
requirePragma
は使用しない。- この場合、
requirePragma
は必要ありません。Prettierは.prettierignore
で指定されていないファイルを整形します。
- この場合、
- CI/CDやGitフックでPrettierを実行する。
- 新規作成されたファイルがPrettierの整形ルールに準拠していることを確認するため、CI/CDパイプラインやPre-commitフックでPrettierのチェック(
prettier --check
)を実行します。
- 新規作成されたファイルがPrettierの整形ルールに準拠していることを確認するため、CI/CDパイプラインやPre-commitフックでPrettierのチェック(
利点
- 新規コードから整形ルールが適用されるため、徐々に整形されたコードが増えていく。
- 既存のコードに一切触らないため、レガシーコードの破壊リスクがない。
欠点
.prettierignore
の管理が少し複雑になる場合がある。- コードベース全体でスタイルが統一されない(既存と新規で混在する)。
ESLintとの連携 (推奨されるアプローチ)
PrettierとESLintは、それぞれ異なる役割を持つツールですが、密接に連携させることでより強力なコード品質管理が可能です。Prettierは「スタイル」に特化し、ESLintは「コードの品質や潜在的なバグ」に焦点を当てます。
Insert Pragma
の代替として直接的に機能するわけではありませんが、Prettierの導入・管理方法として非常に一般的なアプローチです。
方法
- eslint-config-prettier の導入
- ESLintの整形ルールとPrettierの整形ルールが競合しないように、ESLintの設定でPrettierのルールを無効化します。
npm install --save-dev eslint-config-prettier
.eslintrc.js
にprettier
を追加します。
// .eslintrc.js module.exports = { extends: [ // 他のESLint設定 'eslint:recommended', // ... // Prettierとの競合を避けるために最後にprettierを追加 'prettier', ], // ... };
- eslint-plugin-prettier の導入 (任意だが便利)
- Prettierの整形ルールに違反している箇所をESLintのエラーとして報告させるプラグインです。これにより、Prettierのルール違反もESLintの警告/エラーとしてIDEで確認できるようになります。
npm install --save-dev eslint-plugin-prettier
.eslintrc.js
にplugin:prettier/recommended
を追加します。
// .eslintrc.js module.exports = { extends: [ // ... 'plugin:prettier/recommended', // これでprettierプラグインが有効になり、configも適用される ], // ... };
- Gitフック (Husky + lint-staged) の利用
- コミット前にステージングされているファイルのみを対象に、ESLint(とPrettier)を実行し、自動的に整形またはチェックを行います。これにより、不適切なコードがリポジトリにコミットされるのを防ぎます。
npm install --save-dev husky lint-staged
package.json
に設定を追加:
// package.json { "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{js,jsx,ts,tsx,json,css,md}": [ "prettier --write", "eslint --fix", // ESLintで自動修正も行う場合 "git add" // 整形・修正されたファイルをステージングし直す ] } }
利点
- 開発体験が向上する(IDEで整形エラーがリアルタイムで表示されるなど)。
- Gitフックにより、常にフォーマットされたコードがコミットされることを保証できる。
- ESLintとPrettierが共存し、それぞれの強みを活かせる。
- 既存のコードに一括で適用する場合、大きな変更が発生する。
- 初期設定が少し複雑になる。