ロゴテキスト ロゴ

    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
    都内でフリーランスのエンジニアをやってます。フロントとアプリ開発メインに幅広くやってます。