GitHub + npmのモジュール公開前チェックリスト

## はじめに

この記事はnpmパッケージを公開する前に、確認するべきポイントを記録、共有するためのものです。パッケージを公開する前のチェックリストとしてご利用ください。

### 前提とする読者

- JavaScript / TypeScriptの開発経験がある
- GitHubを利用している
- npmのアカウントを持っている

:::note warn
この記事ではnpm自体の解説やアカウントの作成方法については取り扱いません。
:::

### 前提とする環境

- node.js v18.15.0
- npm v9.5.0
- TypeScript v5.1.3

:::note warn
対象となるパッケージのメジャーバージョンが変わると、記事の内容がそのまま適用できないかもしれません。記事を読む前に、お手元の環境をご確認ください。
:::

:::note alert
この記事と記事内のサンプルコードは、npmパッケージを一般公開することを前提に書かれています。プライベートnpmパッケージを作成する場合は、サンプルコードをそのまま利用せず読み替えてください。
:::

## package.json

package.jsonはnpmパッケージの公開に必要な情報を含んでいます。公開前にファイルをメンテナンスしましょう。

### npm initからはじめる

package.jsonをテンプレートから作成している場合、npmに公開するためのフィールドが抜けているかもしれません。[`npm init`コマンド](https://docs.npmjs.com/creating-a-package-json-file#running-a-cli-questionnaire)はpackage.jsonがすでに作成されているプロジェクトでも再実行でき、必要なフィールドを対話式で追加してくれます。

```shell
npm init --scope=[あなたのnpmユーザー名]
```

### パッケージ名にはスコープをつける

https://docs.npmjs.com/cli/v9/using-npm/scope

パッケージ名のスコープはnpm v6から導入された仕組みです。これから公開するパッケージには原則としてスコープをつけましょう。

### versionは0.1.0から

https://docs.npmjs.com/about-semantic-versioning

npmに公開するパッケージは[セマンティックバージョニング](https://semver.org/lang/ja/)のルールに従いましょう。バージョン1.0.0は、APIの仕様が固まったリリース版です。もしあなたのパッケージが初期開発フェーズにあり、今後も破壊的なAPIの変更があるならバージョンは0.1.0から開始しましょう。

[セマンティックバージョニング2.0.0 FAQより](https://semver.org/lang/ja/#0yz%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E5%88%9D%E6%9C%9F%E3%81%AE%E9%96%8B%E7%99%BA%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%81%AE%E5%8F%96%E3%82%8A%E6%89%B1%E3%81%84%E3%81%AF%E3%81%A9%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%81%B9%E3%81%8D%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%81%8B)

> 0.y.zのような初期の開発フェーズにおけるバージョンの取り扱いはどのようにすべきでしょうか？
> 一番簡単な方法は0.1.0からで開発版をリリースし、その後のリリースのたびにマイナーバージョンを上げていけばよいでしょう。

### filesフィールドを追加する

https://qiita.com/masato_makino/items/656f4fbb1595cbcdc23d

package.jsonの[filesフィールド](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#files)は、npmで公開するファイルを指定するための設定です。単体テストファイルやトランスパイル前のソースファイルは、パッケージの動作に必要ではありません。動作に必要のないファイルは積極的に除外しましょう。

## README

READMEはユーザーがパッケージを理解するために最初に触れる情報です。ユーザーの視点に合わせてREADMEの情報を整理、追加しましょう。

### ユーザーが一番知りたい情報はライセンス

https://shields.io/category/license

パッケージを利用しようと考えるユーザーがもっとも欲しい情報は、ライセンスの形態です。READMEには必ずライセンスを明記しましょう。また、ライセンス表記をREADMEの先頭に表示するためにバッジを利用することも検討してください。

### 文章よりも画像、画像よりも動画

https://qiita.com/masato_makino/items/80e35d6c790f771ace43

パッケージを一般公開する場合、ユーザーはそのパッケージの背景となる情報を共有していません。あなたのパッケージの核となる機能を、文章だけではなく画像や動画を使って説明しましょう。核となる機能を読み取れなかったユーザーは、ごく短時間であなたのリポジトリから離脱します。

## CI/CD

[GitHub Actions](https://github.co.jp/features/actions)はGitHubの提供するCI/CD環境です。まずは最低限のテスト環境を構築し、その後は徐々にあなたのプロジェクトに機能を取り込んでいきましょう。

### `tsc`だけのテストでもないよりはずっといい

あなたがTypeScriptでパッケージの開発を行なっている場合、最初の一歩として`tsc`コマンドをCI/CD環境に組み込みましょう。後述するブランチ保護ルールと併用することで、ビルド不可能なコードのマージを防げます。

#### 単体テストを追加していく

最低限のCI環境が構築できたら、[Jest](https://jestjs.io/ja/)などのテスティングフレームワークを導入していきましょう。テストを書くことで、パッケージの品質を維持できるほか、破壊的な変更とバージョン変更のタイミングを明確化できます。

### GitHubの機能を取り込んでいく

テスト環境が整ったら、次はGitHub Actionsをテスト以外の処理にも利用していきましょう。

#### npm publish

手動でnpmの公開コマンド実行はヒューマンエラーの原因となります。GitHub Actionsを利用して、リリース操作をトリガーとして自動化しましょう。

https://docs.github.com/ja/actions/publishing-packages/publishing-nodejs-packages


まずはnpmのアクセストークンをGitHubのシークレットに登録します。

```shell
gh secret set NPM_TOKEN --body "あなたのnpmシークレット"
```

次にワークフローファイルを作成します。

_▼.github/workflows/npm_publish.yml_

```yml
name: Publish to NPM
on:
  release:
    types: [created]
jobs:
  npm-publish:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: "18"
          cache: "npm"
          registry-url: "https://registry.npmjs.org"
      - run: npm ci
      - run: npm run build
      - name: Publish package on NPM 📦
        run: npm publish --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
```

[GitHub上でリリースを作成する](https://docs.github.com/ja/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release)と、その操作をトリガーにワークフローが起動します。事前に登録されたアクセストークンをもとに、npmにパッケージを公開します。

#### Dependabot 

Dependabotは、GitHubのセキュリティ自動化ツールです。Dependabotは依存パッケージに更新版がある場合、自動でバージョンアップ用のプルリクエストを作成します。依存パッケージの更新はパッケージの維持に欠かせない作業です。プルリクエスト作成をトリガーにテストを実行すれば、依存パッケージの更新がパッケージを破壊しないかを検証しながら作業を進められます。

https://docs.github.com/ja/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

[公式ドキュメントのサンプル](https://docs.github.com/ja/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#example-of-a-basic-setup-for-three-package-managers)をもとに、Dependabotの設定ファイルを作成し、`.github/dependabot.yml`に保存します。

_▼.github/dependabot.yml_

```yml
version: 2
updates:

  # Maintain dependencies for GitHub Actions
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

  # Maintain dependencies for npm
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
```

これで、ワークフロー内で利用してる[アクション](https://github.com/marketplace?type=actions)と、npmパッケージの更新が1週間に1回確認されます。確認頻度は`interval`で変更できますので、あなたのパッケージの性質に合わせて調整してください。

#### branch protection rule（ブランチ保護ルール）

ブランチ保護ルールは、指定したブランチに対して特定の操作を禁止する機能です。

- デフォルトブランチへの直接プッシュを禁止
- テストを通過していないプルリクエストのマージを禁止
- ブランチの削除を禁止

などに利用できます。

https://docs.github.com/ja/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule

ブランチ保護ルールは誤操作によるデフォルトブランチの破壊を防ぎます。公開パッケージの価値はユーザーと開発者の信頼感によって成り立っています。ブランチ保護はユーザーとの信頼感を維持するために欠かせません。

## パッケージの粒度

### 大きすぎるよりも小さすぎるほうがずっといい

パッケージを開発している間に「こんな機能があったらいいのではないか」というアイデアが湧いてくると思います。そうした場合、その機能は別のパッケージに切り分けられないかと考えてみてください。パッケージを小さく保つことは、メンテナンス性を引き上げます。

GitHub Actionsの機能向上によって、複数のパッケージを維持する作業が簡単になりました。パッケージが肥大化しそうな場合は切り分けを検討してみてください。

## 個人的な感想

npmやGitHub Actionsには膨大な機能があります。パッケージ公開の作業を通じて、なぜその機能が必要だったのかの理解が進みました。「このコードまた書いてるな」と思ったあなたは、ぜひパッケージを公開してみてください。

以上、ありがとうございました。