自分のみ/社内のみに公開して複数のリポジトリから使えるプライベートなライブラリを公開したい。
そんな場面に遭遇した事はありませんか?
例えば、社内の複数のリポジトリで使い回す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の対応言語など
公式ページに一覧が載っています
https://docs.github.com/ja/packages/learn-github-packages/introduction-to-github-packages
- JavaScript
- Ruby
- Java
- mvn, gradle
- .NET
- Dockerfile
dockerはその他にもコンテナイメージも公開出来るようです!
社内のみのイメージ作って使いまわして等出来たら強力そうですね。
GitHub Packagesを使うための準備(サンプルプロジェクト作成)
パッケージとして公開するための参考用プロジェクトを作成します。
ここではtsを使った簡単な関数を用意します。
TypeScriptの参考プロジェクトを用意
まずtsを実行出来る環境を用意
# package.json作成
$ yarn init -y
# tsを使えるように
$ yarn add -D typescript
# tsconfig.jsonを作成
$ npx tsc --init
tsconfig.jsonを設定
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./dist",
"declaration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
rootDir
・outDir
の設定を追加。
型定義もexportしたいため"declaration": true
も設定。
残りはnpx tsc --init
で作られたデフォルトの状態のままにしました
src/index.ts
に参考用のtsファイルを追加
export function hello(name: string = "world"): string {
return `Hello ${name}! `;
}
tsc
コマンドでビルドを行える事を確認
# ビルドを行う(dist/に書き出される)
$ npx tsc
# エラーが起きなければビルド成功(console.logを仕込んでいないので特に何も起きない)
$ node dist/index.js
.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の設定が重要になってきます!
{
"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 組織名}/{リポジトリ名}
のように指定します。
例えば今回の私の場合だと以下のようになります
{
"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で指定した値になります
普段自分がインストール際はそこまで意識しなくてもいい部分、
自分が公開する側になるので重要になってきます!
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翻訳] これは公開時に使用される設定値のセットです。
ここで設定している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に公開する
方法がいくつかあり、その中でもメジャーそうなものをいくつかご紹介します
- ローカルで
npm publish
を実行する - GitHub Actionsを用いる(おすすめ)
1の方法はGitHubでトークンの用意・毎回npm publish
を実行する必要が出てきて手間なため、
最終的には2がおすすめ!
ただ、
まずローカルで実行して感覚を掴みたかったので私は1.の方法から試してみました。
【前提】GitHub Packagesの認証方法について
GitHub Packagesへのアップロードを行うためにはトークンを用います。
トークンには
GITHUB_TOKEN
- 個人用アクセス トークン(
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 publish
でパッケージをアップロードするためにnpm login
で
- Username・・GitHub ユーザー名
- Password・・個人用アクセストークン (クラシック)
を設定してね、となります。
個人用アクセストークンを取得
Passswordに設定するための個人用アクセストークンを取得します
GitHubにアクセスし、 右上の自分のプロフィールアイコンより
Settings > Developer settings > Personal access tokens の順にアクセス
https://github.com/settings/tokens
Generate new token > Generate new token(classic) を選択
ここではアップロードまで行うため write:packages
にチェックを入れGenerate tokenします。
ここでは解説用のため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
ログインした状態で見た場合
ログインせずに見た場合
このようにプライベートな状態で公開が出来ている事が分かります!
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を追加
・・・
"scripts": {
"build": "tsc"
},
・・・
肝となるGitHub Actions用のymlファイルは公式と以下のページを参考にさせていただきました!mm
GitHub Packagesのnpm registryを利用してパッケージを公開してみた|SHIFT Group 技術ブログ|note
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出来ます!
ローカルでnpm publish
を行った時と同じく
自身のPackagesページにパッケージが出来るのはもちろん
GitHub Actionsを使った場合は自動的にリポジトリとGitHub Packagesが紐付きます
GitHub Packagesを利用する
パッケージをGitHub Packagesに限定公開出来たので、最後にこのパッケージを利用します。
利用の手順は以下のようになります
- read:packagesのトークンを取得
- 読み込む側に.npmrcを用意
- パッケージをインストール
- 利用する
1. read:packagesのトークンを取得
GitHubにアクセスし、 右上の自分のプロフィールアイコンより
Settings > Developer settings > Personal access tokens の順にアクセス
https://github.com/settings/tokens
Generate new token > Generate new token(classic) を選択
ここではアップロードまで行うため read:packages にチェックを入れGenerate tokenします。
2. 読み込む側に.npmrcを用意
.npmrcを用意します!
.npmrcとはnpmレジストリ(今回であればGitHub Packages)からダウンロードする際の設定などを記載出来るファイルで
@{GitHubのユーザー名 or 組織名}:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=<取得したトークンの値>
今回は上記のようにread:packagesを内包したトークンの値を記載
今回の私のケースだと以下のように記載しました
@yuki-takara:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=xxxxxxxxxx
またトークンの値は
- チームメンバー毎に発行する
- 環境に応じて使い分ける
といったユースケースが発生するので環境変数を使うとより便利です。
@{GitHubのユーザー名 or 組織名}:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
export NPM_TOKEN=<取得したトークンの値>
3. パッケージをインストール
いよいよインストールします!
パッケージのインストール方法は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でエラーが起きずに使用できれば成功です!