GitHub Packagesを用いてプライベートに自分のライブラリを公開する!

投稿日
GitHub Packagesを用いてプライベートに自分のライブラリを公開する!

自分のみ/社内のみに公開して複数のリポジトリから使えるプライベートなライブラリを公開したい。


そんな場面に遭遇した事はありませんか?



例えば、社内の複数のリポジトリで使い回すReactのコンポーネントを作ったけど、

npmに公開するのは違うし、各リポジトリにコピーして作って多重管理するのも嫌だしなぁ・・🤔

という場面は結構あるあるじゃないかと思います。




そんな時に便利なのがGitHub Packages


簡単にいうと第三者には見えない(インストール出来ない)

  • 社内限定公開
  • 仲間内のみのプライベート公開

のような、

GitHub上で権限を持った人のみがインストール出来るパッケージを公開する事が出来ます



この記事ではGitHub Packagesで公開する方法をjs/tsを用いて記載します

検証した環境

1 yarn 1.22.19
2 npm 9.4.0
3 typescript 4.9.5

GitHub Packagesの金額

GitHub Packagesはフリープランでも使用出来ます!

https://github.co.jp/features/packages#pricing

GitHub Packagesの金額について

有料プランとはストレージ・データ転送量などに差があるので

良く使うようであればプランを上げる、といった選択肢が取れるのはありがたいですね ☺️


GitHub Packagesの対応言語など

公式ページに一覧が載っています

https://docs.github.com/ja/packages/learn-github-packages/introduction-to-github-packages


  • JavaScript
  • Ruby
  • Java
    • mvn, gradle
  • .NET
  • Dockerfile


dockerはその他にもコンテナイメージも公開出来るようです!

https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry


社内のみのイメージ作って使いまわして等出来たら強力そうですね。



GitHub Packagesを使うための準備(サンプルプロジェクト作成)

パッケージとして公開するための参考用プロジェクトを作成します。

ここではtsを使った簡単な関数を用意します。


TypeScriptの参考プロジェクトを用意

まずtsを実行出来る環境を用意

# package.json作成
$ yarn init -y
# tsを使えるように
$ yarn add -D typescript
 
# tsconfig.jsonを作成
$ npx tsc --init


tsconfig.jsonを設定

tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "rootDir": "./src",
    "outDir": "./dist",
    "declaration": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

rootDiroutDirの設定を追加。

型定義もexportしたいため"declaration": trueも設定。


残りはnpx tsc --initで作られたデフォルトの状態のままにしました





src/index.tsに参考用のtsファイルを追加

src/index.js
export function hello(name: string = "world"): string {
  return `Hello ${name}! `;
}


tscコマンドでビルドを行える事を確認

# ビルドを行う(dist/に書き出される)
$ npx tsc
 
# エラーが起きなければビルド成功(console.logを仕込んでいないので特に何も起きない)
$ node dist/index.js


.gitignoreも設定

.gitignore
node_modules/
dist/


最終的なディレクトリ構成は以下のようになりました

$ tree -L 3
.
├── README.md
├── dist
│   ├── index.d.ts
│   └── index.js
├── node_modules
│   └── typescript
│       ├── LICENSE.txt
│       ├── README.md
│       ・・・
├── package.json
├── src
│   └── index.ts
├── tsconfig.json
└── yarn.lock


GitHub Packagesで公開するための設定

GitHub Packagesを使って公開出来るようpackage.jsonを設定します。


普段の開発時では設定しない項目もあり、かつこのpackage.jsonの設定が重要になってきます!

package.json
{
  "name": "@{GitHubのユーザー名 or 組織名}/{リポジトリ名}",
  "version": "0.0.1",
  "main": "dist/index.js",
  "types": "dist/index.d.js",
  "publishConfig": {
    "access": "restricted",
    "registry": "https://npm.pkg.github.com/"
  },
  "files": ["dist"],
  "license": "UNLICENSED",
  "devDependencies": {
    "typescript": "^4.9.5"
  }
}

重要な部分をピックアップします



name

"name": "@{GitHubのユーザー名 or 組織名}/{リポジトリ名}",

@{GitHubのユーザー名 or 組織名}/{リポジトリ名} にします。

インストールを行う際もyarn add @{GitHubのユーザー名 or 組織名}/{リポジトリ名}のように指定します。


例えば今回の私の場合だと以下のようになります

package.json
{
  "name": "@yuki-takara/github-packages-sample",
  ・・・
}
# インストールする際
$ yarn add @yuki-takara/github-packages-sample


version

"version": "0.0.1",

GitHub Packagesで公開するこのパッケージのバージョンを指定します



例えばaxiosの場合の 1.3.4 といった部分がversionで指定した値になります

axiosの場合のバージョン

普段自分がインストール際はそこまで意識しなくてもいい部分、

自分が公開する側になるので重要になってきます!



main

"main": "dist/index.js",

呼び出す側が参照するファイルを指定します


types(optinal)

"types": "dist/index.d.js",

型定義ファイルを指定。

型定義をexportしない場合は指定不要です


publishConfig

"publishConfig": {
  "access": "restricted",
  "registry": "https://npm.pkg.github.com/"
},

最重要項目の1つ!

パッケージを公開するための設定を記載します

https://docs.npmjs.com/cli/v9/configuring-npm/package-json#publishconfig

This is a set of config values that will be used at publish-time.

[DeepL翻訳] これは公開時に使用される設定値のセットです。


package.json | npm Docs より引用



ここで設定している2つの値はそれぞれ以下のような意味になります

  • access
    • 公開範囲設定
    • public(公開)・restricted(制限付き公開)が設定可能
    • デフォルト値: public
  • registry
    • パッケージの配布先
    • デフォルト値: ”https://registry.npmjs.org/
      • (デフォルトのままだとnpmにパッケージを配布しようとする)

つまりこの2つを設定する事で

GitHub Packagesに制限付きで公開するよ」という意味合いになります。




files

"files": ["dist"],

これも重要!



files はパッケージを公開する際に含めるディレクトリ・ファイルを指定します。



  • 【前提】読み込む側で指定するdist/フォルダはgitignoreしている
  • GitHub Actionsでビルドを行ってdist/を作成 → 公開

今回ザックリ上記の流れになりますが、

filesを記載しないと一部だけアップロードされる、dist/が一切アップロードされないなど結果がマチマチでした 😅



ですのでfilesは必須で指定した方がパッケージとして安定します。




license(optinal)

"license": "UNLICENSED",

記載してなくても問題ない項目ではあるものの、ない状態でyarnを実行しようとすると

warning package.json: No license field

と表示されるので指定しています。



"license": "UNLICENSED"というのは「他人に権利を譲らない」という意味合いになるそうです。


GitHub Packagesを使った限定公開の場合、

社内もしくはプライベートのみの公開かと思うため UNLICENSED が適しているイメージ。



private(optinal)

"private": false,

これは指定しなくて問題なしです(デフォルトでfalseが入るため)



注意点として private:true を指定するとpublishコマンド実行時にエラーが起きます!

$ npm publish
・・
npm ERR! This package has been marked as private
npm ERR! Remove the 'private' field from the package.json to publish it.



GitHub packagesに公開する

方法がいくつかあり、その中でもメジャーそうなものをいくつかご紹介します

  1. ローカルで npm publish を実行する
  2. GitHub Actionsを用いる(おすすめ)

1の方法はGitHubでトークンの用意・毎回npm publishを実行する必要が出てきて手間なため、

最終的には2がおすすめ!


ただ、

まずローカルで実行して感覚を掴みたかったので私は1.の方法から試してみました。


【前提】GitHub Packagesの認証方法について


GitHub Packagesへのアップロードを行うためにはトークンを用います。


トークンには

  1. GITHUB_TOKEN
  2. 個人用アクセス トークン(write:packagesを含むもの)

の2種類があり、それぞれ

  • GITHUB_TOKEN・・GitHub Actions
  • 個人用アクセストークン・・ローカルでのnpm publish

で使用します


GITHUB_TOKENは発行不要、個人用アクセストークンは自分で発行が必要

となります



1. ローカルで npm publish を実行する

まず何も設定せずにローカルでnpm publishを試しに実行してみます

$ npm publish
・・・
npm ERR! code ENEEDAUTH
npm ERR! need auth This command requires you to be logged in to https://npm.pkg.github.com/
npm ERR! need auth You need to authorize this machine using `npm adduser`

publishする許可がないためエラーになります。

そのため、GitHub Packagesにアップロードするための準備から行います




この辺りの設定方法も公式ドキュメントにかなり詳しく書いてくれてまして

npm レジストリの操作 - GitHub Docs


要約するとnpm publishでパッケージをアップロードするためにnpm login

  • Username・・GitHub ユーザー名
  • Password・・個人用アクセストークン (クラシック)

を設定してね、となります。



個人用アクセストークンを取得

Passswordに設定するための個人用アクセストークンを取得します



GitHubにアクセスし、 右上の自分のプロフィールアイコンより

Settings > Developer settings > Personal access tokens の順にアクセス

https://github.com/settings/tokens

GitHubのpersonal access tokenのページ


Generate new token > Generate new token(classic) を選択

ここではアップロードまで行うため write:packages にチェックを入れGenerate tokenします。

write:packagesにチェックを入れてトークンを生成する

ここでは解説用のため30日で期限切れになるようなトークンを生成しています



npm login & npm publish

公式に書かれているようにコマンドを入力

$ npm login --scope=@NAMESPACE --auth-type=legacy --registry=https://npm.pkg.github.com
npm notice Log in on https://npm.pkg.github.com/
Username: <GitHubのユーザー名・組織名>
Password: <↑で取得した write:packages 権限のトークンの値>
Logged in to scope @NAMESPACE on https://npm.pkg.github.com/.



再度実行してみると

$ npm publish
・・・
npm notice Publishing to https://npm.pkg.github.com/ with tag latest and restricted access
+ @yuki-takara/github-packages-sample@0.0.1

アップロード出来ました!


アップロードが完了すると自分のPackagesタブに表示されます。URLとしては下記のようなURL

https://github.com/{自分のアカウント名}?tab=packages




ログインした状態で見た場合

Packagesを自分から見た場合

ログインせずに見た場合

Packagesをログインせずに見た場合

このようにプライベートな状態で公開が出来ている事が分かります!




2. GitHub Actionsを用いる(おすすめ)

おすすめのGitHub Actionsを用いた方法を記載します!



認証にGITHUB_TOKENを用いますが、GITHUB_TOKENは設定や発行をせずに使用する事が出来ます。


そのため、GitHub Actionsでpublishするための設定を記載すれば

それだけでパッケージの公開が行えます。


1.ローカルで npm publish を実行する

を実行し、既にGitHub Packagesにパッケージが存在する人は1度削除する事をおすすめします…!


なぜかというと

パッケージがある状態でGitHub Actionsからpublishしようとしたところ

リポジトリとの紐付け・権限周りなどで私がかなり苦しめられたためですw


最終的に 1度削除 → 再度GitHub Actionsでpublish を行う事ですんなり成功しました。



手順は

パッケージのトップページ > Packages settings

下の方の Danger Zone にある Delete this package から行えます




publishを行う前にTypeScriptのビルドを行うので、package.jsonにnpm-scriptsを追加

package.json
・・・
"scripts": {
  "build": "tsc"
},
・・・



肝となるGitHub Actions用のymlファイルは公式と以下のページを参考にさせていただきました!mm

GitHub Packagesのnpm registryを利用してパッケージを公開してみた|SHIFT Group 技術ブログ|note

.github/workflows/auto-publish.yml
name: Publish package to GitHub Packages
 
on:
  push:
    branches:
      - main
 
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      packages: write
      contents: read
 
    steps:
      - uses: actions/checkout@v3
 
      - uses: actions/setup-node@v3
        with:
          node-version: 16
          registry-url: https://npm.pkg.github.com/
 
      - name: install
        run: yarn install
 
      - name: build
        run: yarn build
 
      - name: publish
        run: yarn publish
        env:
          NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

以下の部分を記載しないとPermission installation not allowed to Create organization packageというエラーが起きます

permissions:
  packages: write
  contents: read



上記記述後、mainブランチにpushするとパッケージをpublish出来ます!

GitHub Actionsを使ってパッケージをpublishする


ローカルでnpm publishを行った時と同じく

自身のPackagesページにパッケージが出来るのはもちろん

Packagesを自分から見た場合


GitHub Actionsを使った場合は自動的にリポジトリとGitHub Packagesが紐付きます

GitHubのリポジトリにもPakcagesとして登録される


GitHub Packagesを利用する

パッケージをGitHub Packagesに限定公開出来たので、最後にこのパッケージを利用します。


利用の手順は以下のようになります

  1. read:packagesのトークンを取得
  2. 読み込む側に.npmrcを用意
  3. パッケージをインストール
  4. 利用する

1. read:packagesのトークンを取得

GitHubにアクセスし、 右上の自分のプロフィールアイコンより

Settings > Developer settings > Personal access tokens の順にアクセス

https://github.com/settings/tokens

GitHubのpersonal access tokenのページ


Generate new token > Generate new token(classic) を選択

ここではアップロードまで行うため read:packages にチェックを入れGenerate tokenします。

read:packagesにチェックを入れてトークンを生成する


2. 読み込む側に.npmrcを用意

.npmrcを用意します!


.npmrcとはnpmレジストリ(今回であればGitHub Packages)からダウンロードする際の設定などを記載出来るファイルで

.npmrc
@{GitHubのユーザー名 or 組織名}:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=<取得したトークンの値>

今回は上記のようにread:packagesを内包したトークンの値を記載



今回の私のケースだと以下のように記載しました

.npmrc
@yuki-takara:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=xxxxxxxxxx



またトークンの値は

  • チームメンバー毎に発行する
  • 環境に応じて使い分ける

といったユースケースが発生するので環境変数を使うとより便利です。

.npmrc
@{GitHubのユーザー名 or 組織名}:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
.zshrc
export NPM_TOKEN=<取得したトークンの値>

3. パッケージをインストール

いよいよインストールします!



パッケージのインストール方法はGitHub Packagesのページにも記載されています

GitHub Packagesのページのインストール方法

↑ではバージョンを指定していますが、

バージョンを指定しなければ最新バージョンをインストールしてくれます

$ npm install @{GitHubのユーザー名 or 組織名}/{リポジトリ名}
# or
$ yarn add @{GitHubのユーザー名 or 組織名}/{リポジトリ名}


私の今回作ったパッケージだとこのように。

$ yarn add @yuki-takara/github-packages-sample
・・・
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ @yuki-takara/github-packages-sample@0.0.1
info All dependencies
└─ @yuki-takara/github-packages-sample@0.0.1

npmで公開されているパッケージと同じようにインストール出来るのは感動です!😭




4. 利用する

インストールしたパッケージを利用してみます


ここでもimport時の指定は '@{GitHubのユーザー名 or 組織名}/{リポジトリ名}' となります

// import { hello } from '@{GitHubのユーザー名 or 組織名}/{リポジトリ名}'
import { hello } from '@yuki-takara/github-packages-sample'
 
console.log(hello('world!'))
// => Hello world!!

importでエラーが起きずに使用できれば成功です!

プロフィール画像
Yuki Takara
都内でフリーランスのエンジニアをやってます。フロントとアプリ開発メインに幅広くやってます。