VPNに接続することは、npmのレジストリ設定を一日に二回書き換えることであるべきではありません。プロジェクト単位の設定ファイルのスコープエントリを使えば、社内パッケージを一方のレジストリへ、それ以外を公開レジストリへ送れ、切り替えも、金曜の午後に置き忘れる上書きも不要です。問題は、これが名前の解決にしかならないことであり、ルーティング、認証情報、設定の優先順位は別々の三つの問題で、それぞれ独自の仕方で失敗します。

二つの名前、二つの行き先

npmのパッケージ名にはスコープがあるか、ないかのどちらかです。スコープ付きの名前は@記号とスコープ識別子で始まり、設定が対応付けられるのはこの識別子だけです。パッケージの他の要素は対応付けに関係しません。レジストリは、パッケージが社内か公開かでリクエストを見ることは決してなく、名前だけを見ます。

つまり下のファイルは三行で二つの意図を表しており、公開パッケージは公開レジストリへ、社内スコープのパッケージはそのホスト用のトークンとともに社内レジストリへ送られます。

registry=https://registry.npmjs.org/
@acme:registry=https://packages.corp.example/
//packages.corp.example/:_authToken=${NPM_TOKEN}

スコープ、ホスト、変数名は、組織が実際に提供するものに置き換えてください。大事なのは構造であり、例の値ではありません。二行の設定が方針のすべてを担うからこそ、コピーするのではなく理解する価値があります。

対応付けとネットワークは頭の中で別の引き出しに分けてください。スコープエントリは到達できないホストを到達可能にはできませんし、動くトンネルはパッケージがどのレジストリに属するかをnpmに教えることはできません。

ファイルは正しい順序で書く

npmが複数のファイルを読むとしても、考えるときはプロジェクトのファイルを最初に置いてください。プロジェクトディレクトリの .npmrc は、リポジトリを通じて同僚が受け取るファイルなので、個人のトークンではなく共有の方針を表すべきです。そのファイルはレビュー担当者が読むファイルでもあります。一目で確認できる大きさに保ってください。

組織が別段の決定をしていない限り、既定の registry 行は公開レジストリを指したままにしてください。これを削除すると、マシンはユーザー単位のファイルの記述に依存するようになり、それが二台のノートPCで違う結果を生む典型的な暗黙の依存です。

スコープ行はワイルドカードではありません。スコープ外の名前は既定を使い続け、自分で書いていない依存のすべてに望む挙動はこれです。

コミットする前に、実際のインストールの代わりに使い捨てのパッケージ名で解決結果を確認し、失敗しても何も失わないようにしてください。

認証情報はプロジェクトではなくホストに属する

認証エントリはレジストリのホストに、レジストリが必要とする場合はパスにも紐づきます。トークン行がスコープではなく二重スラッシュとホストで始まるのはそのためです。その位置にホストがあると分かれば、行の残りは無意味な記号には見えなくなります。それはアドレスであり、トークンはそこに結び付いています。

環境変数を使えば、リテラルのトークンをリポジトリのファイルの外に置けます。ただしトークンが見えなくなるわけではなく、プロセスの環境には現れますし、設定を出力するコマンドがそれを明かすことがあります。

変数は組織が承認したローカルまたはCIの認証情報の仕組みで用意し、ドキュメントにコピーされうる例に本物のトークンを決して貼らないでください。

二つのレジストリが関わるなら、それぞれに専用のエントリを与えます。修飾のない単一のトークン設定は、良くても曖昧で、悪ければ誤ったホストへ送られます。

誤ったレジストリが勝つとき

設定は階層になっており、有効な値は今編集したファイルの値とは限りません。プロジェクト設定、ユーザー設定、グローバル設定、環境変数がすべて関わります。この階層があるからこそ、修正が自分のマシンでは効いて同僚のコンテナでは効かないのです。また、議論する前に有効な値を出力する価値がある理由でもあります。

CIでよくある原因は環境変数で、ジョブがレジストリを一度設定すると以降のすべてのステップがそれを引き継ぎます。二番目に多いのは、開発者のマシンのユーザー単位ファイルがリポジトリの記述を上書きしている場合です。

他の何かをデバッグする前に、スコープ付きとスコープなしの名前それぞれについて、有効な設定と解決されたレジストリを出力してください。その二つの答えが期待どおりなら問題はネットワークで、そうでなければ問題は設定であり、VPNをいくら弄っても解決しません。

コミット前のチェックリスト

スコープ名が実際に公開されたパッケージと一致していること、既定のレジストリが明示されていること、トークン行が正しいホストを指していることを確認してください。スコープの打ち間違いは、パッケージが公開レジストリから解決され、同名の他人のモジュールが返ってくるという、最も奇妙な失敗を生みます。トークンをデバッグする前に名前を確認してください。

プライベートレジストリに、インストールを実行するコンテキストのマシンから到達できることを確認してください。ブラウザからだけでは足りず、プロキシやコンテナがシェルと違うルーティングを持つ場合、この区別が効いてきます。

そのうえで、キャッシュされたパッケージのないきれいなチェックアウトで挙動を確認してください。新入りの同僚が何を体験するかを示す唯一のテストは、まっさらなインストールです。

関連記事