every Tech Blog

株式会社エブリーのTech Blogです。

GitHub Packagesを利用したnpmパッケージの社内利用

every Tech Blog Advent Calendar 3日目の記事になります!

こんにちは 開発本部データ&AIチームでデータエンジニアを担当している塚田です。

今回は、挑戦WEEK中にGitHub Packagesを利用したnpmパッケージの社内利用を行いましたのでその内容についてご紹介します。

挑戦WEEKとは 開発メンバーが通常の各事業部のロードマップから離れ、技術的に何かに集中して挑戦する1週間 としており、 弊社CTOの今井がTech Blogにて説明しておりますので、よろしければ併せてご覧ください。

tech.every.tv

エブリーで利用している画像について

エブリーではDELISH KITCHENトモニテTIMELINEの3つのメディアを運営しています。 どのメディアも画像を多数利用して構成しており、画像配信基盤はシステムを構成する重要な一機能となっています。

画像配信基盤の問題点

それぞれのメディアで画像処理 → 画像返却 → 配信という処理の流れは共通しています。

ただし、画像処理の部分で画像変換はほぼ共通しているのですが、変換前処理がそれぞれ独自実装されている状況でした。

改善方針

独自処理が発生してしまうのは避けられない部分ではありますが、画像変換に関しては統一できる処理であるため共通化する方針となりました。

前置きが長くなりましたが、画像変換の共通処理のみを行うnpmパッケージとして切り出しGitHub Packagesで社内利用する流れを整備したので、事例として紹介します。

前提

  • GitHub Organizationを利用している
    • Organizationでなくても実行可能ですが、今回はOrganizationを利用した場合の説明となります
  • 開発端末でNode.jsの実行環境が整備されている
    • 執筆時はNode.js 20.9.0を利用しています

package.jsonの作成(初期化)

それでは実際にGitHub Packagesに登録するパッケージを作成します。

npm init -y

後述の手順でpackage.jsonの変更を行いますのでデフォルトのままで問題ありません。

S3からファイル名を取得する処理を実装

今回はサンプルとして、Amazon S3に保存しているファイルを取得しデータ返却する を実装します。

パッケージのインストール

npm i -D typescript @types/node
npm i -S @aws-sdk/client-s3

今回は上記のパッケージをインストールします。

用途に合わせて他のパッケージもインストールしてください。

tsconfig.jsonの作成

npx tsc --init

作成されたtsconfig.jsonを以下のように修正します。
(自動的に作成されたものや今回の説明に必要ないものは削除しています)

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

S3ファイル情報の取得ロジック

以下のサンプルプログラムをsrc/index.tsとして作成します。

import { GetObjectCommand, GetObjectCommandOutput, S3Client } from '@aws-sdk/client-s3'

export async function getObject(bucket: string, key: string) {
  const params = {
    Bucket: bucket,
    Key: key
  }
  const command = new GetObjectCommand(params)
  const response = await new S3Client().send(command)
  const str = await response.Body?.transformToString();
  return str
}

package.jsonの変更

GitHub Packagesに登録できるようpackage.jsonを以下のように変更します。

今回はs3-file-getterというパッケージ名にしています。

GitHubの環境に合わせて{Organization名}{リポジトリ名}を変更してください。

{
  "name": "@{Organization名}/s3-file-getter",
  "version": "0.1.0",
  "description": "",
  "main": "dist/index.js",
  "files": [
    "dist"
  ],
  "scripts": {
    "prepublishOnly": "npm run build",
    "build": "tsc -d"
  },
  "author": "",
  "license": "",
  "repository": {
    "type": "git",
    "url": "https://github.com/{Organization名}/{リポジトリ名}.git"
  },
  "dependencies": {
    "@aws-sdk/client-s3": "^3.450.0"
  },
  "devDependencies": {
    "@types/node": "^20.9.0",
    "typescript": "^5.2.2"
  }
}

ここで重要なのはnamerepositoryとなっており、それ以外は環境によって適宜変更してください。

GitHub Packagesへ登録

GitHub ActionsワークフローYAMLファイルの作成

自動的にGitHub Packagesへ登録させたいので、GitHub Actionsの設定を行います。

GitHubクイックスタートが用意されているので、それを流用し以下の設定を.github/workflows/publish.ymlとして作成します。

name: npm package publish

on:
  release:
    types: [created]

jobs:
  publish-gpr:
    runs-on: ubuntu-latest
    permissions:
      packages: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          registry-url: https://npm.pkg.github.com/
      - run: npm ci
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

リリースの作成

作成したpublish.ymlはリリースが新規作成された際に実行される設定となっているため、GitHubでリリースを作成します。

この時package.jsonのversionが既にGitHub Packagesで登録されている場合エラーとなるため、導入するプロジェクトのリリースフローによって柔軟に変更してください。

今回はリリース前にversionの更新を行なっているものとして運用します。

GitHub Packagesの確認

GitHub Actionsの処理が完了すると以下のように対象リポジトリTOPの右下のPackagesに今回作成したかったnpm packageが登録されています。

今回作成したs3-file-getterのリンクを選択するとパッケージのバージョンなどのサマリーが確認できます。

GitHub Packagesの利用

登録だけしても利用できないと意味がないので利用するために必要な手順を記載します。

ローカルの場合

Personal Access Token (Classic)を作成

GitHub Packagesへの認証を行うドキュメントが用意されているので、これに従いAccess Tokenを作成します。

パッケージの読み込みができれば良いので、今回Scopeはread:packagesのみを選択します。

.npmrcの作成

以下の設定を.npmrcとして作成します。

{Organization名}{作成したAccess Token}を環境に合わせて置換してください。

registry=https://npm.pkg.github.com/{Organization名}
//npm.pkg.github.com/:_authToken={作成したAccess Token}

注意:.npmrcにAccess Tokenを直書きしているので、.gitignoreで管理対象外にするなど誤って公開される状況にならないよう防御策を取るようにしてください。

GitHub Packagesからパッケージのインストール

.npmrcの設定をしていてもGitHub Packages以外のパッケージは今まで通りインストール可能です。

GitHubの環境に合わせて{Organization名}を変更してください。

npm i -D typescript @types/node
npm i -S @{Organization名}/s3-file-getter

パッケージの利用

他のパッケージと同様にimportすることで利用できます。

import { getObject } from '@{Organization名}/s3-file-getter';

const data = async () => {
    console.log(await getObject('{bucketName}', '{key}'))
}

data()

GitHub Actionsの場合

GitHub Packagesにアクセスできるリポジトリを設定

パッケージのサマリー画面にPackage settingsのリンクがあるので、クリックします。

パッケージを利用したいリポジトリを以下の機能から追加することで参照可能な権限を付与できます。

GitHub ActionsのWorkFlowを設定する

パッケージを利用するための設定のみ記載しています。

環境に合わせて適宜変更してください。

jobs:
  sample:
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          registry-url: https://npm.pkg.github.com/
      - run: npm ci
        env:
          NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

おわりに

GitHub Packagesを利用した、社内でのみ参照可能なnpmパッケージの作成方法と利用方法について一連の流れを紹介しました。

今回のサンプルは公開しても問題ないものですが、共通の処理をパッケージにして利用したいけどロジックは外部に公開したくないなどのシチュエーションで利用できると感じています。

画像配信基盤の改善はデータエンジニアとして関わるのはあまりないことだと思うのですが、挑戦WEEKが良いきっかけとなりました。

この後のAdvent Calendarでも挑戦WEEKに関連する投稿を予定していますので、ぜひチェックしてみてください。