goコマンドに特定のディレクトリを無視させたいときは空のgo.modファイルを置いておく

タイトルでほとんど説明しましたが、Go Modulesが有効な環境で、module-awareなコマンドに特定のディレクトリを無視させるには、無視させたいディレクトリにダミーのgo.modファイルを設置しておくとよいです。ファイルの内容は空で構いません。

Githubにサンプルコードを置いておいたので、参考にしてください。

github.com

解説

パッケージパターンを引数として受け取るgoコマンドのサブコマンドを使うとき、...というワイルドカードを使うと、特定のディレクトリツリー内のパッケージをまとめて指定できて便利です。

例えば

$ go generate ./...

というコマンドは、カレントディレクトリ(.)以下のすべてのパッケージを対象にしてgo generateコマンドを実行します。

これはパッケージがたくさんある場合にひとつずつ指定せずに済むので便利なのですが、この方法だとgoコマンドがすべてのディレクトリツリーを走査してしまうので、実行に時間がかかる場合があります。

例えば、GoとNode.jsのソースコードが同居しているコードベースがあったとき、node_modulesディレクトリにはGoのソースコードは含まれていないので、goコマンドがこのようなディレクトリを見ないようにできると、パフォーマンス上のメリットがあります。

goコマンドは_または.から始まるディレクトリや、testdataというディレクトリは無視する*1ので、ディレクトリをリネームできる場合はそうすればいいのですが、node_modulesのようにディレクトリ名を制御できないこともあります。

これに対処するには、ダミーのgo.modファイルを当該ディレクトリに設置し、goコマンドにそのディレクトリ以下を別のモジュールとして認識させるという方法が使えます。

個人的には筋の良い解決策とは思えないのですが、Goチームとしてはgoコマンドに特定のディレクトリを無視する機能を追加する予定はないようです*2

node_modulesを無視したい場合はpostinstallスクリプトを使う

一般にnode_modulesディレクトリはバージョン管理システムで管理されないため、go.modファイルが必ずnode_modulesに配置されるようにするには一工夫必要です。

ワークアラウンドとしては、package.jsonpostinstallスクリプトに空のgo.modファイルを作成するようなスクリプトを指定するとよいでしょう(とりあえずnode_modules生成後に自動でgo.modを配置するという用途にはこれで十分ではあるものの、GoのツールチェインのためのファイルをNode.jsの仕組みで生成させるのはいかがなものか……とも思いますが)。