mizdra's blog

ぽよぐらみんぐ

GitHub Packages を npm install するための手段あれこれ

概要

  • 社内向けの npm packages を publish するのに GitHub Packages が便利
    • GitHub 内で完結してお手軽 & Actions を使って自動リリースフローを作りやすい
  • しかし GitHub Packages に上がっている npm packages を npm install するには少々手間がかかる
  • 従って、GitHub Packages に上がっている npm packages を使うプロジェクトでは、npm install をするあらゆる場面で、PAT による認証を挟んでおかなければならない
    • local で docker-compose up する時
    • actions/jenkins 上で Node.js の CI を走らせる時
    • リリース用の docker image を CI 上で作る時
    • ...などなど
  • この時 PAT をどう管理するか、というのが意外と悩ましい (と個人的に思っている)
    • 何か楽な方法がないか色々考えてみる

案1: 社内の共有GitHubアカウントで発行した PAT をリポジトリの .npmrc に埋め込んでおく

共有トークンをリポジトリにベタ書きし、リポジトリに直接 commit してしまう、という案。

.npmrc:

//npm.pkg.github.com/:_authToken=<社内の共有GitHubアカウントで発行したトークンをここに貼る>
@example-corp:registry=https://npm.pkg.github.com/
  • メリット
    • npm は npm install 時に自動でカレントディレクトリにある .npmrc を見て認証してくれるので、これさえ書けば local だろうと actions だろうと jenkins だろうと、全ての場所で動く
  • デメリット
    • リポジトリにトークンが commit されてしまう

案2: プロジェクトを動かしたい人ごとに PAT を発行して、.npmrc に直書きしてもらう & GitHub Secrets などの仕組みを使う

共有トークンを commit するのを避けて、個人で PAT を発行して、それを使ってもらうという案。

.env などに個人で発行した PAT を埋め込んでおき、dotenv などと組み合わせて以下のように .npmrc から読み込む。

.npmrc:

//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
@example-corp:registry=https://npm.pkg.github.com/

これだけだと local でしか PAT が設定されず、actions や jenkins 上では認証ができないので、適時 GitHub Secrets や Jenkins の Credentials を使って PAT を環境変数 NPM_TOKEN に設定するようにしておく。

サードパーティツールへのパスを設定 - Cloud https://docs.github.com/ja/actions/reference/encrypted-secrets *1

  • メリット
    • トークンがリポジトリに commit されない
  • デメリット
    • プロジェクトを使いたい個人ごとにトークンを発行しないといけない
      • 一度セットアップすれば良いとはいえちょっと手間

package が公開可能な場合

社内向けだけど OSS にして良いとか、公開可能な場合は他にも取れる手段がある。

案3: npmjs.com に公開する

  • npmjs.com に public で package を publish する方法
  • デメリット
    • 公開可能な package でないと利用できない
    • npmjs.com のアカウントを作るのがちょっと手間
      • まあ一度作ってしまえば良いのだけど

案4: git 形式で npm install する

  • 予め GitHub リポジトリを公開しておき、 npm install https://github.com/example-corp/xxx.git#v1.0.0 でインストールする方法
  • デメリット
    • 公開可能な package でないと利用できない
    • 事前ビルドが必要な package との相性が悪い
      • というのも、通常 Git リポジトリにはビルドの成果物が commit されていない & git 形式の npm install は単に git に commit されているファイルをコピーして node_modules 配下に置くだけで、npm run build などはしてくれないため
    • npm update / yarn upgrade や renovate でアップデートできない *2
      • データソースが npm repository でないため、標準的なツールを使ったアップデートができない

@example-corp:registry=<URL> の注意点

.npmrc に記載する @example-corp:registry=<URL>@example-corp をスコープとするパッケージ全てを <URL> から取得する使用になっています。つまり @example-corp/package-a, @example-corp/package-b, ... は全て <URL> から取得されます *3。その挙動の影響で「GitHub Packages にホストされている @example-corp スコープのパッケージ」と「npmjs.com にホストされている @example-corp スコープのパッケージ」を共存させることができないという既知の問題があります。public package は npmjs.com、private package は GitHub Packages、みたいな運用をしているとハマります。もしそういう使い方をする予定であれば、GitHub Packages or npmjs.com のどちらかに寄せる、という対応を別途検討したほうが良いでしょう *4

この問題については以下の記事が詳しいので、それぞれ読んでみるとよいと思います。


どの方式も一長一短あって難しい。皆さんはどうしてますか?

*1:Organization Secrets というやつがオススメです

*2:npm update / yarn upgrade は手元で試して確認した。renovate も https://github.com/mizdra-sandbox/git-npm-package-test/issues/1 で試して確認した。dependabot は試してないので知りません。

*3:URL に無かったら npmjs.com から取得するといった fallback も一切ないので、URL にないパッケージのインストールは失敗する。

*4:GitHub Packages と npmjs.com でスコープ名を変えるという素朴な workaround もある

ポケットモンスター・ポケモン・Pokémon・は任天堂・クリーチャーズ・ゲームフリークの登録商標です.

当ブログは @mizdra 個人により運営されており, 株式会社ポケモン及びその関連会社とは一切関係ありません.