2026年8月3日
2026年8月3日
Bazelで大規模プロジェクトのビルドを管理する方法:導入の判断基準と基本設定
Bazel は、ビルドの入力と出力を厳密に宣言させることで、変更があった部分だけを再ビルドし、結果をキャッシュで共有できるビルドツールです。複数の言語やパッケージを抱える大規模なモノレポで効果を発揮する一方、小さな WordPress テーマ単体には過剰になりがちです。この記事では、Bazel が向いている規模の見極め方、MODULE.bazel と BUILD ファイルの基本、キャッシュと依存関係の調べ方までを説明します。
Bazelが向いているプロジェクト・向いていないプロジェクト
Bazel の強みは次の 3 点です。
- 増分ビルド: どのファイルが何に使われるかを BUILD ファイルで宣言するため、変更の影響を受けるターゲットだけを再ビルド・再テストできます。
- 再現性: ビルドはサンドボックス内で宣言された入力だけを使って実行されます。宣言漏れがあるとエラーになるので、「自分の環境でだけ動く」ビルドが生まれにくくなります。
- キャッシュの共有: ビルド結果をディスクやリモートのキャッシュに保存し、別のマシンや CI から再利用できます。
こうした性質が活きるのは、たとえば次のようなケースです。
- Go や Java のバックエンド、TypeScript のフロントエンド、WordPress のテーマなど、複数の言語・成果物がひとつのリポジトリにある
- CI のビルドやテストに時間がかかり、毎回すべてを実行するのが負担になっている
- 開発者が多く、ビルド手順の差異によるトラブルが繰り返し起きている
反対に、テーマやプラグインがひとつだけで、ビルドが npm run build と composer install で数十秒で終わる規模なら、Makefile や npm scripts のほうが学習コストも保守の手間も小さく済みます。Bazel は BUILD ファイルの保守という継続的なコストを伴うため、「ビルドの遅さや不安定さが実際の問題になっているか」を導入の判断基準にするのが現実的です。
また、PHP には Bazel の公式ルールセットがありません。WordPress のテーマやプラグインを Bazel に載せる場合は、PHP ファイルを filegroup でまとめたり、genrule で既存のビルドコマンドを包んだりする形になり、Go や Java ほどの恩恵は受けにくい点も理解しておく必要があります。
基本の用語
- ワークスペース(リポジトリ):
MODULE.bazelが置かれたディレクトリをルートとする、Bazel の管理範囲です。 - パッケージ:
BUILD.bazel(またはBUILD)ファイルがあるディレクトリ単位のまとまりです。 - ターゲット: パッケージ内で定義されるビルド対象です。
//themes/my-theme:bundle_cssのような ラベル で指定します。//はワークスペースのルート、:の後ろがターゲット名です。 - ルール: ターゲットの作り方を定義するものです。
filegroupやgenruleは Bazel 本体に含まれ、言語ごとのルールはrules_goやrules_javaなどの外部ルールセットとして提供されています。
Bazeliskでバージョンを固定して導入する
Bazel 本体を直接インストールするより、Bazelisk を使う方法が一般的です。Bazelisk は bazel コマンドの代わりとして動き、リポジトリ直下の .bazelversion ファイルに書かれたバージョンの Bazel を自動で取得して実行します。チーム全員と CI で同じバージョンを使えるようになるため、バージョン差による挙動の違いを防げます。
Bazelisk は各 OS のパッケージマネージャーや GitHub のリリースページから入手できます。.bazelversion には公式のリリースページで確認した具体的なバージョン番号を 1 行で書いておきます。
MODULE.bazelとBUILDファイルを書く
MODULE.bazel(Bzlmod)
現在の Bazel では、外部依存を MODULE.bazel で管理する Bzlmod が標準です。以前使われていた WORKSPACE ファイルは Bazel 8 で既定で無効になり、将来のバージョンで削除される方針が示されています(2026年10月現在。移行状況は Bazel の公式ドキュメントとリリースノートで確認してください)。古い記事のサンプルが WORKSPACE 前提で書かれていることも多いので注意してください。
最小構成の MODULE.bazel は次のとおりです。
module(
name = "my_wp_monorepo",
version = "0.1.0",
)
外部のルールセットを使うときは、bazel_dep(name = "...", version = "...") を追記します。利用できるモジュールとバージョンは Bazel Central Registry(BCR)で調べられます。
BUILD.bazel
テーマのディレクトリに置く BUILD.bazel の例です。外部ルールセットを使わず、Bazel 本体に含まれるルールだけで動きます。
# themes/my-theme/BUILD.bazel
filegroup(
name = "php_sources",
srcs = glob(["**/*.php"]),
visibility = ["//visibility:public"],
)
genrule(
name = "bundle_css",
srcs = [
"css/base.css",
"css/layout.css",
],
outs = ["style.bundle.css"],
cmd = "cat $(SRCS) > $@",
)
filegroup は複数のファイルをひとつのターゲットとして束ねるルールで、他のパッケージから //themes/my-theme:php_sources として参照できます。visibility を指定しないと、既定では同じパッケージ内からしか参照できません。
genrule は任意のシェルコマンドでファイルを生成するルールです。$(SRCS) は srcs に並べたファイル、$@ は出力ファイルに置き換わります。サンドボックスが有効な環境(Linux や macOS の既定)では、srcs に書いていないファイルはサンドボックス内に存在しないため、コマンドから読もうとすると失敗します。このエラーは「入力の宣言漏れ」を教えてくれるもので、Bazel の再現性を支える仕組みそのものです。
ビルドと出力の確認
bazel build //themes/my-theme:bundle_css
ls bazel-bin/themes/my-theme/
生成物はワークスペース直下に作られる bazel-bin シンボリックリンクの先に出力されます。もう一度同じコマンドを実行すると、入力が変わっていないため実際の処理は行われず、すぐに完了するはずです。css/base.css を編集してから再実行すると、bundle_css だけが再生成されます。
ワークスペース全体をビルドするには bazel build //...、テストをまとめて実行するには bazel test //... を使います。
npmやComposerのビルドを組み込むときの注意
JavaScript のビルドについては、rules_js などのコミュニティ製ルールセットがあり、node_modules を含めて Bazel の管理下に置けます。ただし設定量は多く、既存の webpack や Vite の設定をそのまま移せるとは限りません。まずはフロントエンドのビルドを従来どおり npm で行い、Bazel は成果物をまとめる役割から始めるなど、段階的に取り込むほうが失敗が少なくなります。
genrule の中で npm や composer を直接呼ぶ方法もありますが、ネットワークアクセスやサンドボックス外のファイルに依存するため、Bazel の再現性やキャッシュの利点が損なわれます。採用する場合は、その部分だけはキャッシュが効きにくいことを前提に設計してください。
キャッシュの設定
設定はワークスペース直下の .bazelrc に書いておくと、すべての bazel コマンドに適用されます。
# .bazelrc
build --disk_cache=/var/tmp/bazel-disk-cache
test --test_output=errors
--disk_cache を指定すると、bazel clean を実行した後やブランチを切り替えた後でも、以前のビルド結果を再利用できます。ディスクキャッシュは使い続けると大きくなるので、容量を監視し、必要に応じて古いデータを削除する運用を決めておきます。新しいバージョンにはキャッシュの自動削除に関するオプションも追加されていますが、名称や扱いが変わることがあるため、使用するバージョンのドキュメントで確認してください。
チームや CI でキャッシュを共有するには、--remote_cache でリモートキャッシュのサーバーを指定します。リモートキャッシュは書き込み権限の管理が重要です。誰でも書き込める状態にすると、改ざんされた成果物が他の開発者や CI に配られる恐れがあるため、CI からのみ書き込みを許可し、開発者のマシンは読み取り専用にする構成がよく使われます。
依存関係を調べる
Bazel は依存関係のグラフを持っているので、bazel query で影響範囲を調べられます。
# ワークスペース内のターゲットを一覧表示
bazel query //...
# bundle_css が依存しているもの
bazel query 'deps(//themes/my-theme:bundle_css)'
# php_sources に依存しているターゲット(影響範囲)
bazel query 'rdeps(//..., //themes/my-theme:php_sources)'
rdeps は「このファイル群を変更したら何に影響するか」を調べるときに役立ちます。CI で変更されたファイルに関係するテストだけを実行する仕組みも、この情報を土台に組み立てられます。
導入を進めるときの順序
- まずブランチを切り、既存のビルド手順を残したまま Bazel を試します。
- ビルドが単純で独立した部分(CSS の結合、生成ファイルの作成など)から BUILD ファイルを書きます。
bazel build //...とbazel test //...が CI で安定して通るようになってから、ディスクキャッシュやリモートキャッシュを導入します。- 効果が確認できた範囲だけを従来の手順から置き換えます。
一度にすべてを移そうとすると、BUILD ファイルの不備とキャッシュ設定の問題が同時に起きて原因を切り分けにくくなります。
まとめ
- Bazel は複数言語・大規模なモノレポで増分ビルドとキャッシュ共有の効果が大きい。小規模な WordPress テーマ単体には過剰になりやすい。
- PHP には公式ルールセットがないため、WordPress 関連は
filegroupやgenruleでの扱いが中心になる。 - Bazelisk と
.bazelversionでバージョンを固定し、外部依存はMODULE.bazel(Bzlmod)で管理する。 - 入力の宣言漏れによるエラーは再現性を守るための仕組み。
bazel queryで依存関係と影響範囲を確認できる。 - リモートキャッシュは書き込み権限を絞り、導入は小さな範囲から段階的に進める。