Node.jsプロジェクトのための実践的なCIセットアップ
すべてのNode.jsプロジェクトは、手動テストが信頼できなくなる時点に到達します。誰かがプッシュ前にリンターを実行し忘れます。テストはローカルでは通るのに、チームメイトのマシンでは失敗します。依存関係の更新が本番環境を壊すのに、誰も互換性の問題に気づきません。
適切に構造化されたCIパイプラインは、これらの問題を自動的に検出します。本記事では、GitHub Actionsを使用した堅実なベースラインとなるNode.js CIセットアップがどのようなものか、各コンポーネントがなぜ存在するのか、そしてパイプラインが長期的に機能し続けるために各要素をどのように考えるべきかを説明します。
重要なポイント
- CIパイプラインでは、ロックファイルに基づいた決定論的で再現可能なビルドのために、
npm installではなくnpm ciを使用する - 高速に失敗するようにパイプラインを構造化する:依存関係のインストール → リントと型チェック → テスト実行
- バージョンマトリックスを使用して、実際にサポートするNode.jsバージョンに対してテストを行い、Active LTSリリースに焦点を当てる
- エラーを迅速に検出し、よりクリーンな失敗メッセージを生成するために、テスト前に静的解析を実行する
- 過度に複雑なキャッシングや過剰なバージョン固定を避けることで、パイプラインをシンプルで保守しやすく保つ
ベースラインとなるJavaScript CIパイプラインが行うべきこと
Node.jsプロジェクトのための実践的なCIパイプラインは、3つの関心事を処理します:一貫した依存関係の確保、コード品質の検証、そして関連するNodeバージョン全体でのテスト実行です。
パイプラインは高速に失敗し、可視的に失敗する必要があります。何かが壊れた場合、開発者は即座に知る必要があり、その理由を理解する必要があります。
コアステージ
信頼性の高いGitHub Actions Node CIワークフローは、次のシーケンスに従います:
依存関係のインストール → リントと型チェック → テスト実行
各ステージは次のステージをゲートします。コードが正しく解析されない場合、完全なテストスイートを実行する意味はありません。
依存関係のインストール:npm ciが重要な理由
npm CI のベストプラクティスで最も重要なのは、パイプラインでnpm installの代わりにnpm ciを使用することです。
npm ciは、CIにとって重要な2つのことを行います:
- ロックファイルに記載されている内容を正確にインストールします—バージョン解決なし、サプライズなし
- 最初に
node_modulesを削除し、クリーンな状態を確保します
この決定論的な動作は、CI環境がロックファイルで指定された内容と一致することを意味します。ビルドが失敗した場合、その失敗が依存関係のドリフトによって引き起こされたものではないことがわかります。
ロックファイル(npmの場合はpackage-lock.json、pnpmの場合はpnpm-lock.yaml、Yarnの場合はyarn.lock)は、リポジトリにコミットする必要があります。これがないと、npm ciは機能せず、再現性が失われます。
Corepackによるパッケージマネージャーの管理
チームがpnpmまたはYarnを使用している場合、Corepackがパッケージマネージャーのバージョン管理を処理します。依存関係をインストールする前に、ワークフローで有効にします。これにより、CIを含むすべての人が、package.jsonで指定された同じパッケージマネージャーバージョンを使用することが保証されます。
バージョンマトリックス:Node.jsリリース全体でのテスト
バージョンマトリックスを使用すると、複数のNode.jsバージョンに対してパイプラインを同時に実行できます。ほとんどのプロジェクトでは、Active LTSに対するテストで十分です。より広範な互換性要件を持つプロジェクトでは、現在のMaintenance LTSを追加することがあります。
マトリックスアプローチは、互換性の問題を早期に検出します。新しいNodeバージョンで動作する構文機能は、ユーザーが依存している古いバージョンには存在しない可能性があります。
マトリックスは最小限に保ちます。すべての可能なバージョンに対してテストすると、比例した利益なしにCI時間が増加します。プロジェクトが実際にサポートするバージョンに焦点を当てます。
Discover how at OpenReplay.com.
テスト前のリントと型チェック
テストスイートの前に静的解析を実行します。ESLintはコード品質の問題を検出します。TypeScript(使用している場合)は型エラーを検出します。どちらもほとんどのテストスイートよりも高速に実行されます。
この順序が重要な理由は2つあります:
- より速いフィードバック:構文エラーは数分ではなく数秒で表面化します
- よりクリーンな失敗:リンティングエラーは、同じ根本的な問題によって引き起こされた不可解なテスト失敗よりも診断が容易です
これらのツールをエラー時にビルドを失敗させるように設定します。ビルドを失敗させない警告は無視されます。
テスト実行と失敗の可視性
テストステージは明確な出力を生成する必要があります。テストが失敗した場合、開発者は問題を迅速に特定する必要があります—理想的には、折りたたまれたログセクションを掘り下げることなく。
ほとんどのテストランナーは、CI対応の出力フォーマットをサポートしています。Jest、Vitest、およびNodeの組み込みテストランナーはすべて、CI環境を検出し、それに応じて出力を調整します。
次のプラクティスを検討してください:
- カバレッジ付きでテストを実行するのは、実際にカバレッジデータを使用する場合のみ
- テストランナーがサポートし、テストが独立している場合はテストファイルを並列化する
- 開発ブランチでは高速に失敗し、mainでは完全なスイートを実行する
キャッシング:期待値に関する注意
依存関係のキャッシングはインストール時間を短縮できますが、その利点は様々です。依存関係の少ない小規模プロジェクトでは、改善がほとんど見られない場合があります。大規模なモノレポでは、実行ごとに数分節約できる可能性があります。
キャッシングを過度に複雑にしないでください。actions/setup-nodeの組み込みキャッシングは、一般的なケースを処理します。インストールが遅い場合は、複雑さを追加する前に測定してください。
パイプラインの保守性を維持する
頻繁な更新が必要なCIパイプラインは負担になります。アクションバージョンを特定のパッチに固定することを避け、互換性のある更新を受け取るメジャーバージョンタグを使用します。可能な場合は、正確なバージョンではなく、リリースラインでNodeバージョンを参照します。
目標は、頻繁なメンテナンスなしに確実に実行されるJavaScript CIパイプラインです。更新が必要な場合、変更は反応的ではなく意図的であるべきです。
まとめ
堅実なNode.js CIセットアップには、複雑な設定は必要ありません。npm ciで決定論的に依存関係をインストールし、テスト前に静的解析を実行し、サポートするNodeバージョンに対してテストします。失敗を可視化し、パイプラインを保守できるほどシンプルに保ちます。
このベースラインから始めてください。解決すべき特定の問題がある場合にのみ、複雑さを追加してください。
よくある質問
npm ciは、バージョンを解決せずにロックファイルで指定された内容を正確にインストールし、クリーンな状態のために最初にnode_modulesを削除します。npm installはロックファイルを更新し、異なるバージョンを解決する可能性があります。CIの場合、npm ciはコミットされたロックファイルと正確に一致する決定論的なビルドを提供します。
プロジェクトが実際にサポートするバージョンに対してテストします。ほとんどのプロジェクトでは、Active LTSバージョンで十分です。より広範な互換性が必要な場合は、Maintenance LTSを追加します。比例した利益なしにCI時間が増加するため、すべての可能なバージョンに対するテストは避けてください。
リンティングはほとんどのテストスイートよりも高速に実行され、構文とコード品質の問題を数秒で検出します。最初に実行することで、より速いフィードバックが得られ、よりクリーンな失敗メッセージが生成されます。リンティングエラーは、同じ根本的な問題によって引き起こされた不可解なテスト失敗よりも診断が容易です。
プロジェクトのサイズによります。依存関係の少ない小規模プロジェクトでは、キャッシングによる改善はほとんど見られません。大規模なモノレポでは、実行ごとに数分節約できます。actions/setup-nodeの組み込みキャッシングから始め、複雑さを追加する前に実際のインストール時間を測定してください。
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.