GitHub Packagesを使ってJavaScript libraryを管理する

## はじめに
今までGoではgo getを使った共通Packageの管理はしていましたが、JavaScriptではしていませんでした。
しかし、フロント開発で同一デザイナーで同じデザインシステムを採用することとなったシステムを作ることなり、既存システムの資産を効率良く管理できないかと思いGitHub Pakcagesを使うことになったので同様のことを行う方の参考になればと思います。
この記事では、**yanrとnpm**の両方を使った方法を説明させて頂きます。


## GitHub Packagesとは
従来は`npm install` などでinstallできるようにJava script libraryの管理には[npmjs.com](https://www.npmjs.com/)にアカウントを作成しnpmjs.comでlibraryを管理していたが、それらが全てGitHubで完結できるようになった。
なので、npmjs.comのアカウント作成とは不要になり、かつ従来通り`npm install or yarn install`を使ってlibraryをinstallできるようになった。（Library使用側の使い勝手には変更なし）

Public packageは無料でPrivate packageは無料枠があるが場合によっては料金がかかるので[こちら](https://github.com/features/packages#pricing)を確認してください。


## 前提
- GitHubにrepostioryが作成済み
- ディレクトリー構成としては以下の構成を想定しています。

```
.
├── package.json
└── packages
    ├── sample-a
    │   ├── package.json
    │   └── src
    │       └── index.js
    └── sample-b
        ├── package.json
        └── src
            └── index.js
```
pakcagesディレクトリーの下に各種モジュールを配置しているデファクトスタンダートな構成です。

## 下準備をしていく
### ルートディレクトリーにpackage.jsonを作成する
workspace機能を使ってpakcagesディレクトリー配下のpackageを管理していくのでルートディレクトリーにpackage.jsonを作成します。
```sh
npm init
// or
yarn init
```
必須ではないですが、念のため`"private": true`を作成されたpackage.jsonに追記しときます。

### pakcagesディレクトリー配下にpakcageを作っていく
ディレクトリーを作ってから、そのディレクトリーで`yarn init`してもよいですが、面倒なのでルートディレクトリーで`npm init -w packages/DIR_NAME`でまとめて作ってしまいます。
```
npm init -w packages/sample-a
npm init -w packages/sample-b
```

- 作成された各packageに以下のようなsample moduleを追加します
```js
// packages/sample-a/src/index.js
function sayHello(){
    console.log("Hello World Sample A Package");
}

sayHello()

// packages/sample-b/src/index.js
function sayHello(){
    console.log("Hello World Sample B Package");
}

sayHello()
```
- 最後に各Packageのpackage.jsonを修正して準備は完了です。

```json
  "name": "@[GITHUB_USER_NAME or ORG_NAME]/sample-b",
  "version": "1.0.0",
  "description": "sample b package",
  "main": "src/index.js", ← 追記
  "files": [ ←追記
    "src/*"
  ],
  "repository": { ←追記
    "type": "git",
    "url": "https://github.com/<GITHUB_USER_NAME>/<REPOSITORY_NAME>.git",
    "directory": "packages/sample-b"
  },
  "publishConfig": { ←追記
    "registry": "https://npm.pkg.github.com/"
  }
```

1. mainはpackageのエントリーポイントとなるファイル名を指定してください
1. filesはPackageに含めて配信したいファイルやディレクトリーを指定してくだい（webpackなどでバンドルしたファイルのみを配信したい場合は`dist/*`みたいな指定をします）
1. repositoryは、モノリポ構成の場合のみ指定が必須になります。
1. publishConfigはnpmjs.comに向かってPublishしないように設定しといた方が無難です。

## GitHub PakcageにPublishする
- .npmrcを作成し各packageのpackage.jsonと同階層に置く
```.npmrc
//npm.pkg.github.com/:_authToken=<PERSONA_ACCESS_TOKEN>
@<USER_NAME>:registry=https://npm.pkg.github.com/
```
※ Personal access tokenの作成方法は[こちら](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)をご確認ください。

- 各PackageディレクトリーでPusblishコマンドを実行して公開していく
yarnとnpmコマンドのどちらでもPublishできますが、workspacesを設定している場合にコマンドが変わってきますので両方とも記載しておきます。

```sh
// npm
$npm publish --no-workspaces

npm notice 
npm notice 📦  @hog-hog/sample-a@1.0.0
npm notice === Tarball Contents === 
npm notice 307B package.json
npm notice 83B  src/index.js
npm notice === Tarball Details === 
npm notice name:          @yoyo-kikuchi/sample-a                  
npm notice version:       1.0.0                                   
npm notice filename:      @yoyo-kikuchi/sample-a-1.0.0.tgz        
npm notice package size:  353 B                                   
npm notice unpacked size: 390 B                                   
npm notice shasum:        59cdda53231a2447d9f416411c7899f8e8efdc67
npm notice integrity:     sha512-3EL68Kg7q6gs/[...]RHdo/s12gtX1g==
npm notice total files:   2                                       
npm notice 
npm notice Publishing to https://npm.pkg.github.com/
+ @hog-hog/sample-a@1.0.0

// yarn
$ yarn publish

[1/4] Bumping version...
info Current version: 1.0.0
question New version: 1.0.0
[2/4] Logging in...
[3/4] Publishing...
success Published.
[4/4] Revoking token...
info Not revoking login token, specified via config file.
Done in 7.03s.
```

成功後すぐにgithubのrepostioryを確認しても反映されていないので、５分ほど待ってから確認すると以下のようになっていると思います。

![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96623/6c83c9c4-6ee4-6564-ca41-c6e43630dc5f.png)

あとは、使いたい側のRepostioryにも.npmrcを作成し `yarn add @xxxx/module-a`や `npm install --save @xxxx/module-b`を実行すればinstallできます。

### 関係コマンド
publishする際にversionの重複があるとエラーになるので、手動で変更してもよいですが一応コマンドを記載しときます。
- npm
```
// セマンティックバージョニングのmajorをup
npm version major
// セマンティックバージョニングのminorをup
npm version minor
// セマンティックバージョニングのpatchをup
npm version patch

npm publish
```

- yarn
```
// セマンティックバージョニングのmajorをup
yarn publish --major
// セマンティックバージョニングのminorをup
yarn publish --minor
// セマンティックバージョニングのpatchをup
yarn publish --patch
```
yarnの方がpublishコマンドにオプションをつければ一発で終わるので楽ですね。

今回のSampleは[GitHub](https://github.com/yoyo-kikuchi/monorepo-package-sample)で公開しております。

## 参考記事
[GitHub Packagesで複数パッケージを1リポジトリに登録する](https://qiita.com/stm32p103/items/f1d63b66c34706784a8d)
[npm publishする時の注意点](https://qiita.com/__mick/items/e92e3fc001994ca9dfaf)
[npm workspace の使い方](https://qiita.com/frozenbonito/items/8230d4a3cb5ea1b32802)