こんにちは、CTO室の丸山と申します。普段は某CTOからの無茶振りをさばいたりしています。
今回は、いま開発に携わっているプロダクトにおいて、フロントエンド用のライブラリの管理方法について少し調査したことを共有したいと思います。
概要
最近のアプリケーション開発においては、様々なOSSを活用して開発を進めることが当たり前になっています。 一方で、上記と並行して社内で開発したライブラリを社内限りで使わせたいというニーズもあります。
過去に携わったプロジェクトでは、 jFrog や Sonatype Nexus Repository を利用してこれを解決したことがありますが、コスト面/管理面に課題があって今回のニーズには合わなそうでした。
- jFrogは有償版を利用する必要がある
- Sonatype Nexus Repository を利用する場合は、自前でサーバーを構築する必要がある
これらを回避しつつ上記ニーズを解決できないかを探ったところ、npm2系から取り入れられた スコープ の概念と Artifact Registry を組み合わせればあっさりと実現できることがわかりました。
そこで、ライブラリ開発者目線/ライブラリ利用者目線でArtifact Registryを利用したprivate npmパッケージの管理方法を簡単に紹介します。
全体イメージ
- Artifact Registry で private な npm パッケージを管理するためのリポジトリを作成する
- 公開範囲を絞りたいライブラリ群は、上記privateリポジトリに公開する
- ライブラリを利用するアプリケーションは、利用するライブラリに応じてnpmリポジトリを使い分ける
- 公開範囲を絞ったライブラリは、上記privateリポジトリからインストールする
- 上記以外のOSSは通常通りnpmjs.com からインストールする
private npm リポジトリを作成する
プライベート npm パッケージの公開先として、Artifacts Registry を使用します。 gcloud
コマンドを使用して以下のようにリポジトリを作成します。
# 設定値は全て架空の値を使用しています artifacts repositories create sot-private-npm-repo \ --repository-format=npm \ --location=us-central1 \ --description="Private repository for Node.js packages for SOT dev team" \ [--project=sot-private-project]
なお、以降のサンプルでは以下の前提で進めますが、適用する開発プロジェクトに合わせて適宜読み替えてください。
- GCP のプロジェクトとして
sot-private-project
という架空の GCP プロジェクトを作成 - Artifact Registry はアイオワリージョン(us-central1)に作成
- npm リポジトリの名前は
sot-private-npm-repo
として作成
ライブラリの開発者目線
モチベーション
社内で開発したライブラリを社内限りで共有したい
ライブラリの作成から公開までの流れ
まずは、公開範囲を社内に絞るという意図のもと、 @sot-private
スコープの npm パッケージを作成します。
mkdir awesome_lib && cd awesome_lib npm init --scope=@sot-private
初期化作業を完了すると、以下のような package.json
が作成されます。
{ "name": "@sot-private/awsome_lib", "version": "1.0.0", "description": "Awesome library for SO Technologies dev team.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
次に、 @sot-private
スコープで修飾した npm パッケージの公開先として、さきほどArtifacts Registry内に構築した sot-private-npm-repo
を指定します。
# 設定値は全て架空の値を使用しています gcloud artifacts print-settings npm --scope=@sot-private \ --repository=sot-private-npm-repo \ --location=us-central1 \ [--project=sot-private-project]
コマンドを実行した結果、以下のような内容で認証情報が表示されるので、これをライブラリプロジェクト直下の .npmrc
ファイルとして保存します。この設定により、@sot-private
スコープのライブラリの公開先としてArtifact Registory に作成された private リポジトリが関連付けられます。
# 設定値は全て架空の値を使用しています # Insert the following snippet into your project .npmrc @sot-private:registry=https://us-central1-npm.pkg.dev/sot-private-project/sot-private-npm-repo/ //us-central1-npm.pkg.dev/sot-private-project/sot-private-npm-repo/:always-auth=true
Artifacts Registry へのアクセスには GCP の認証情報が必要になります。 Googleが提供する google-artifactregistry-auth ライブラリを使用することで認証処理の複雑さを隠蔽することができます。
先程作成した package.json
に以下の情報を追記し、
"scripts": { "artifactregistry-login": "npx google-artifactregistry-auth", }
以下のコマンドを実行することで、Artifact Registryに認証することができます(認証情報の期限は1時間)。
npm run artifactregistry-login
この方法で認証すると、認証後にユーザーのホームディレクトリに.npmrc
が作成され、そこにArtifactRegistryにアクセスするためのアクセストークンが保存されます。
プロジェクト配下に作成した .npmrc
からは認証情報を分離することができるので、プロジェクト配下の .npmrc
はそのままバージョン管理に含めても問題ありません。
# Macの場合、ユーザーのホームディレクトリ配下に.npmrcが作成される % cat ~/.npmrc //us-central1-npm.pkg.dev/sot-private-project/sot-private-npm-repo/:_authToken=XXXXXXXXXXXXXXXXX
開発したライブラリは、以下のように公開することができます。
# 設定値は全て架空の値を使用しています npm publish \ --scope=@sot-private \ --registry=https://us-central1-npm.pkg.dev/sot-private-project/sot-private-npm-repo/
publishが成功すると、privateリポジトリ配下に以下のようにライブラリがアップロードされていることが確認できます。
ライブラリの利用者目線
モチベーション
社内で開発したライブラリを利用しつつ、他のライブラリは通常通りnpmjsからインストールしたい
アプリケーションでライブラリを利用するまでの流れ
さきほど公開した公開範囲を絞ったライブラリを使用して、アプリケーションを作成します。 まずは、アプリケーションのプロジェクトを作成します。
mkdir awesome_apps & cd awesome_apps npm init
初期化作業を完了すると、以下のような package.json
が作成されます。
{ "name": "awesome_apps", "version": "1.0.0", "description": "Awsome apps which uses awesome library.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
次に、必要なライブラリを追加していきます。例えば emoji-regex を使いたかったら、以下のように追加することで、npmjs.comからインストールすることができます。
npm install emoji-regex
一方で、@sot-private
スコープのライブラリを利用するには、ライブラリの取得先として先程のprivateリポジトリを指定する必要があります。
先程と同様にプロジェクト直下に .npmrc
ファイルを作成し、以下の情報を書き込みます。
@sot-private:registry=https://us-central1-npm.pkg.dev/sot-private-project/sot-private-npm-repo/ //us-central1-npm.pkg.dev/sot-private-project/sot-private-npm-repo/:always-auth=true
また、Artifacts Registry へのアクセスには GCP の認証情報が必要になるため、先程と同様に google-artifactregistry-auth を使用して認証します。
先程作成した awsome_app
の package.json
に以下の情報を追記し、
"scripts": { "artifactregistry-login": "npx google-artifactregistry-auth", }
以下のコマンドを実行することで、Artifact Registryに認証することができます(認証情報の期限は1時間)。
npm run artifactregistry-login
認証が完了していれば、先程作成した @sot-private
スコープのライブラリを private な npm リポジトリからインストールすることができます。
npm install @sot-private/awesome_lib
なお、予め package.json
の dependencies
に書いておけば、npm install
コマンドで一括してインストールすることもできます。
{ "name": "awesome_apps", "version": "1.0.0", "description": "Awsome apps which uses awesome library.", "main": "index.js", "scripts": { "artifactregistry-login": "npx google-artifactregistry-auth", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "@sot-private/awsome_lib": "^1.0.0", "emoji-regex": "^10.2.1" } }
インストールされたライブラリは node_modules
配下に以下のように配置されます。
特に、スコープを指定されているライブラリは、@sot-private
配下に配置されます。
. ├── node_modules │ ├── @sot-private │ │ └── awsome_lib │ └── emoji-regex ├── package-lock.json └── package.json
また、スコープを指定されたライブラリを利用するには、以下のようにインポートします。
// 架空のライブラリなので実際には動きません const awesome_lib = require('@sot-private/awesome_lib');
まとめ
思っていたよりもあっさりとArtifact Registryでprivate npmパッケージを管理することができました。
今回は時間の関係で調査しきれませんでしたが、以下の観点でもう少し調査をすると実際の開発プロジェクトにも安心して適用できそうです。
- CI/CD環境などの
google-artifactregistry-auth
ライブラリが使えない環境でビルドをしたいときに、どのようにArtifact Registryからnpmパッケージを取得するか - 利用者目線のユーザーにはArtifact Registryへの参照権限だけを与えることはできそうか
npm install
は許容するが、npm publish
は許容しないといったことはできるか
少しでも参考になれば幸いです。