初めてのnpm パッケージ公開

#### 履歴
@qsona さんの編集リクエストより記載ミスを修正
@diescake さんの編集リクエストよりコマンドのtypo を修正
ありがとうございます :grin:

注意: 現在はGemnasium はGitLab に統合されたため利用できないようです。代わりはhttps://libraries.io/ あたりになるでしょうか

# NodeJS パッケージの作成にあたって 
NodeJS のパッケージを作成してnpm に登録するときに、実際に行った手順について備忘録として残しておきます。


* 実施環境
<table><tbody>
  <tr>
    <th> OS</th>
    <td> Ubuntu 16.04 LTS</td>
  </tr>
  <tr>
    <th> NodeJS</th>
    <td> 6.0.0</td>
  </tr>
  <tr>
    <th> npm</th>
    <td> 2.15.0</td>
  </tr>
  <tr>
    <th> 作成したパッケージ(GitHub リポジトリ名及びnpm パッケージ名)</th>
    <td> rpncc</td>
  </tr>
</tbody></table>

今回はrpncc という、配列で渡された計算式を逆ポーランド記法に変換/計算したり、逆ポーランド方式の式を通常の式に戻すパッケージを作成しました。
最終的に完成したものは以下のものになります。

- rpncc
    - https://github.com/TsutomuNakamura/rpncc

# npm ユーザの作成 
npm のauthor 情報及びユーザがまだ作成されていない場合は、`npm set`, `npm adduser` コマンドを使ってそれらを登録していきます。


```console:author情報を作成する
$ npm set init.author.name "Tsutomu Nakamura"
$ npm set init.author.email "tsutomu-nakamura@example.com"
$ npm set init.author.url "http://qiita.com/TsutomuNakamura"
```


上記コマンドを実行すると`~/.npmrc` ファイルが作成されその中に入力した情報が格納されます。
次に`npm adduser` コマンドを使ってユーザを登録します。


```console:npmユーザの登録
$ npm adduser
## まだユーザが登録されていない場合は、npm に登録する新規ユーザ情報を入力する。
## 既にnpm ユーザが作成されている場合はそのユーザの情報を入れて、ログインする。
```


# GitHub リポジトリの作成 
GitHub で新規リポジトリを作成します。
今回は逆ポーランド記法(Reverse Polish notation)の計算や変換(calculate/convert)をしてくれるパッケージなので`rpncc` という名前にしておきました。
そのため、`rpncc` という名前のリポジトリを事前に作成しておきます(作成手順は割愛します)。

リポジトリを作成したら、自分のローカル環境にclone しておきます。


```console:clone
$ git clone git@github.com:TsutomuNakamura/rpncc.git
$ cd rpncc
```


# npm init でパッケージの情報を入力 
`npm init` コマンドを実行し、`package.json` ファイルを作成します。
`package.json` ファイルはこのパッケージが他のどのパッケージと依存関係にあるのかといった情報や、build に関する環境情報を記載して他の開発者や他ワークステーションとの間でbuild 環境を共有する手助けをしてくれます。


```console:npminit
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (rpncc)                                                       # <- このパッケージの名前。カッコ内はデフォルト
version: (1.0.0)                                                    # <- バージョン
description: Reverse Polish Notation calculator/converter for js    # <- このパッケージの説明
entry point: (index.js)                                             # <- 何も入力せずEnter (default: index.js)
test command: ava -v                                                # <- テストコマンド。今回はava
git repository: (https://github.com/TsutomuNakamura/rpncc.git)      # <- 何も入力せずEnter (default)
keywords: rpm reverse polish notation rpncc                         # <- keyword を入力。npm search された時の検索キーワード
license: (ISC) MIT                                                  # <- 今回は"MIT" と入力
About to write to /home/tsutomu/Work/gitwork/rpncc/package.json:

{
  "name": "rpncc",
  "version": "1.0.0",
  "description": "Reverse Polish Notation calculator/converter for js",
  "main": "index.js",
  "scripts": {
    "test": "ava -v"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/TsutomuNakamura/rpncc.git"
  },
  "keywords": [
    "rpm",
    "reverse",
    "polish",
    "notation",
    "rpncc"
  ],
  "author": "Tsutomu Nakamura <tsutomu-nakamura@example.com> (http://qiita.com/TsutomuNakamura)",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/TsutomuNakamura/rpncc/issues"
  },
  "homepage": "https://github.com/TsutomuNakamura/rpncc#readme"
}


Is this ok? (yes) 
```


以上で初期状態の`package.json` の作成は完了です。

# 検証やテスト時に依存するパッケージの定義(package.json のdevDependency にパッケージの追記) 
検証やテスト時に依存するパッケージをインストールし、`package.json` の`devDependency`に追記していきます。

具体的に検証、テスト時に依存するパッケージとはテスト自動化や自分の作成したパッケージ本体に依存するパッケージのことを指します。
これらのパッケージを`npm install --save-dev <package name></doe> コマンドを使って、インストールと同時に`package.json` ファイルに定義を追加します。


```console:node--save-dev
$ ava --init                       # npm install --save-dev でも良いがava の場合、ava init でもdevDependency に追記される
$ npm install --save-dev sinon     # 例えばテスト自動化に必要な依存パッケージとしてsinon が必要な場合は--save-dev でインストールする
$ npm install --save-dev rewire    # テスト時に使用するパッケージ
$ npm install --save-dev chance    # プログラム本体に必要なパッケージ
$ cat package.json
  ......
  "devDependencies": {
    "ava": "^0.14.0",
    "chance": "^1.0.2",
    "rewire": "^2.5.1",
    "sinon": "^1.17.4"
  }
  ......
```


また、パッケージインストール時に作成される`node_modules` ディレクトリはコミットする必要が無いので、`.gitignore` に記載しておくようにしてください。

## 補足: 検証、テスト時に依存するパッケージを削除する(package.json のdevDependency のパッケージの削除) 
あとでパッケージが不要になった時に、`package.json` の`devDependency` からパッケージを削除するには、`npm rm --save-dev <package name>` を実行します。


```console:npmrm--save-dev
$ npm rm --save-dev sinon
```


# 本番時に依存するパッケージの定義(package.json のdependency にパッケージの追記) 
本番時に依存するパッケージを`package.json` に追記します。
本番時に依存するパッケージは`npm install --save <package name>` を実行すればOK です。


```console:npminstall
$ npm install --save chance
```


上記コマンドを実行することで`package.json` の`dependencies` にパッケージ名が追記されます。


```json:npminstall時のpackage.json
  ......
  "dependencies": {
    "chance": "^1.0.2"
  }
  ......
```


# プログラムの作成 
では次に、以下のようなファイル構成でプログラムを作成していきます。


```text
rpncc/
  +-- index.js
  +-- package.json
  +-- test/
    +-- test-index.js
```


今回はテスト自動化のava の`--watch` モードを使用し、ファイルの変更が発生するタイミングで随時テスト行われるようにしながら開発を行っていきたいと思います。


```console:テストの実行
$ npm test -- --watch
......
## ファイルに変更が発生したのをトリガーにテストが自動的に実行される
```


テストコードは以下のような形式で作成していきます…。


```javascript:test/test-index.js
import test from 'ava';
import Rpncc from '../index';
import './lib/load_prototypes';

const rpn = new Rpncc();

test('rpn#convert should return "1 2 +" if the value "1 + 2" is passed', t => {
    t.true(rpn.convert(["1", "+", "2"]).equals(["1", "2", "+"]));
});

test('rpn#convert should return "1 2 -" if the value "1 - 2" is passed', t => {
    t.true(rpn.convert(["1", "-", "2"]).equals(["1", "2", "-"]));
});
......
```


パッケージ本体は以下のように作成していきます…。


```javascript:index.js
......
function Rpncc() {
    ......
    this.convert = function(expression) {
        var priority;
        var argument;
        var stack = [], result = [];

        ......

        return result.concat(stack.reverse());
    };
}
module.exports = Rpncc;
```



```console:テスト実行の様子
$ npm test -- --watch
......
  ✔ index › rpn#convert should return "1 2 +" if the value "1 + 2" is passed
  ✔ index › rpn#convert should return "1 2 -" if the value "1 - 2" is passed
```


# GitHub のトップページに、テストに合格した証のTravis CI バッチを貼り付けてる(任意) 
テストに成功したことを表すTravis CI のバッチをあなたのGitHub リポジトリのトップページに貼り付けてみましょう。
Travis CI のサイトにアクセスし、あなたのGitHub アカウントでログインします。

- Travis CI
    - https://travis-ci.org/

ログインしたら、メニューの`+` ボタンをクリックします。

![CreateNPMModule_0000.png](https://qiita-image-store.s3.amazonaws.com/0/70152/e64a5f28-a113-e4fd-8f50-444347a0e793.png)


repositories の"+" の部分をクリックすると、あなたのGitHub のリポジトリが一覧表示されるので、テストを実行したいリポジトリを選択します。
今回は`rpncc` を選択します。
![CreateNPMModule_0001.png](https://qiita-image-store.s3.amazonaws.com/0/70152/25412f7e-a70b-f35b-9a1c-871014bc245b.png)


リポジトリを選択したら歯車のマークをクリックし、どのタイミングでテストを実行させるかを指定します。
今回は`push`, `pull request`が発生した時且つ`.travis.yml` ファイルがあった時のみ実行するようにしておきます。
![CreateNPMModule_0002.png](https://qiita-image-store.s3.amazonaws.com/0/70152/33e49ecb-8aa7-6360-c9e5-fe85425fc50f.png)


上記の設定を行うことで、リポジトリに対してpush やpull request 操作が行われたタイミングでtravis 側のサーバで自動的に`npm install` を実行して依存関係パッケージをインストールし、`npm test` でテストを実行し、結果を報告してくれるようになります。
それでは早速`.travis.yml` を作成し、`git push`してみましょう。


```text:.travis.yml
language: node_js
node_js:
  - "6"
  - "5"
  - "4"
  - "4.4.3"
  - "0.12"
```

`language:` に`node_js` と記載し`node_js:` にサポートするnode のバージョンを列挙していきます。
このversion 番号はnode のバージョン管理パッケージ`nvm` に送られて、指定したNodeJS のバージョンでテストが実行されるようになっています。

その他、NodeJS についての詳細なオプションについては以下のページが参考になります。
- Building a Node.js project
    - https://docs.travis-ci.com/user/languages/javascript-with-nodejs

ファイルを作成したら、commitと push を行います。
今回は開発用branch をmaster にマージしてからpush しています。


```console:gitpushorigin
$ git add .travis.yml
$ git commit -m "Added .travis.yml"
$ git checkout master                  # 開発用のブランチで作業していた場合はmaster ブランチへマージ
$ git merge some_branch                # 〃
$ git push origin master
```


push されると、以下のようにテストが開始されます。
![CreateNPMModule_0003.png](https://qiita-image-store.s3.amazonaws.com/0/70152/49aa73df-2479-5093-5efb-7ab6fda10bd9.png)  

テストが完了すると以下のようにテスト結果が表示されます。
![CreateNPMModule_0004.png](https://qiita-image-store.s3.amazonaws.com/0/70152/41bc497a-d299-ba35-189a-06debfa797c0.png)  

テストに成功したら画面上のバッジをクリックし、バッジのURL を取得してください。
そのURL をGitHub のREADME.md に貼り付けることでGitHub リポジトリのトップにバッジが表示されるようになります。
![CreateNPMModule_0004-02.png](https://qiita-image-store.s3.amazonaws.com/0/70152/6989eb52-e077-85c0-f508-4486203fb1ae.png)


# gemnasium を使って依存関係パッケージ追跡のバッジを作成する(任意) 
【注意: 現在はGitLab に統合されたため利用できないようです。代わりはhttps://libraries.io/ あたりになるでしょうか】<br />
gemnasium を使用してプロジェクト内で使用されている依存パッケージの状態を追跡しましょう。
追跡することで、依存パッケージに新しいバージョンがリリースされたり、セキュリティ上の理由などによりアップデートが必要になった時に通知してくれるようになります。

- gemnasium
    - https://gemnasium.com/

こちらもGitHub アカウントでログインし、対象リポジトリを登録していきます。
`ADD NEW PROJECT` から`HOSTED ON GITHUB` を選択します。

![CreateNPMModule_0005.png](https://qiita-image-store.s3.amazonaws.com/0/70152/07748ea1-fe15-30b2-d840-3a3ac877408b.png)


![CreateNPMModule_0006.png](https://qiita-image-store.s3.amazonaws.com/0/70152/a3d350cc-fa7a-124b-aee9-cfd0bed361c1.png)


初めて作成する場合、次のように権限付与するように聞かれるので、今回は`PUBLIC PROJECT` を選択しておくことにします。

![CreateNPMModule_0007.png](https://qiita-image-store.s3.amazonaws.com/0/70152/a94cd500-b958-6932-5a86-0e751265918f.png)


`ADD PROJECTS FROM GITHUB` 画面が表示されたら自分の名前の対象のリポジトリを選択し、`SUBMIT` ボタンをクリックします。
![CreateNPMModule_0010.png](https://qiita-image-store.s3.amazonaws.com/0/70152/2042164f-77b1-405d-67dc-90c38f38dcda.png)


登録が完了すると依存関係のレポートが表示されますので、リポジトリ名の部分をクリックします。
![CreateNPMModule_0011.png](https://qiita-image-store.s3.amazonaws.com/0/70152/498d0385-39ae-2653-187d-0f2c68db3b8d.png)


リポジトリの設定ボタンを押下し、`Badge` タブを選択するとMARKDOWN 形式のサンプルが表示されるので、それをあなたのGitHub リポジトリの`REAMDE.md` に貼り付けてください。

![CreateNPMModule_0012.png](https://qiita-image-store.s3.amazonaws.com/0/70152/f3d003aa-7266-3397-d6d5-3ead9c40a369.png)

![CreateNPMModule_0013.png](https://qiita-image-store.s3.amazonaws.com/0/70152/c79bc47a-1846-3afc-8b2e-291ea9fb6c15.png)


## その他のバッジについて 
その他、自作badge を載せたい場合はshields.io のサービスを利用すると簡単にできます。
手順は以下の記事がとても参考になりますので、ここでは詳細な説明は割愛させていただきます。

- クラウドサービスを活用して README にバッジをペタペタ貼る
    - http://qiita.com/dtan4/items/13b0ea9edf5b99926446

例えば追加でversion やライセンスのバッジを`README.md` に載せると以下のようになります。

![CreateNPMModule_0014.png](https://qiita-image-store.s3.amazonaws.com/0/70152/4c974451-b6e1-29ff-ae60-a6954a3694a7.png)


# ライセンスファイルの作成 
あなたのパッケージにライセンスを明記しましょう。
今回、自分のパッケージはMIT ライセンスで公開するものとします。

GitHub リポジトリのトップディレクトリに`LICENSE.txt` ファイルを追加し、ライセンス文を明記します。
記載内容は以下のページの文章の`<year>`, `<copyright holders>` の部分を自分の物に書き換えて使用すれば問題無いでしょう。

- The MIT License (MIT) - Open Source Initiative
    - https://opensource.org/licenses/MIT

# npm に公開 
準備ができたら、自作パッケージを公開しましょう。
`rpncc` のGitHub リポジトリに`v1.0.0` のタグを作成し、それを公開します。


```console:npmpublish
$ git tag -a v1.0.0 -m "My first version v1.0.0"
$ git push origin tags/v1.0.0
$ npm publish ./
+ rpncc@1.0.0
```


npm にパッケージが公開されました！
公開されたパッケージはすぐに`npm install` コマンドでインストールできることが確認できます。


```console:npminstall
$ npm install rpncc
```


# patch バージョンのアップ 
パッケージを使用していると後々bug が見つかってくる可能性があります。
bug fix によりパッチを当てたバージョンを公開する場合、ソースコードを修正した後に`npm version patch` コマンドを実行してバージョンを上げ、再度`npm publish` で公開するようにします。


```console
$ npm version patch              # <- v1.0.0 からv1.0.1 にアップ
v1.0.1
$ git tag                        # <- git のtag も自動的に作成される
v1.0.0
v1.0.1
$ git push origin tags/v1.0.1    # <- ただし、git push まではやってくれないので、必要に応じて自分でgit push ...
$ npm publish ./                 # <- npm で公開
```


## マイナーバージョン、メジャーバージョンのアップについて(npm version minor, npm version major) 
マイナーバージョン、メジャーバージョンをアップする場合はそれぞれ`npm version minor`, `npm version major` を使用します。


```console:使用例
$ npm version minor    # v1.0.1 からv1.1.0 にアップ
v1.1.0

$ npm version major    # v1.0.1 からv2.0.0 にアップ
v2.0.0
```


その後は`npm version patch` の時と同様に、必要に応じて`git push`と`npm publish` を実行してください。

# latest, beta 版のtag 指定について 
自分のプログラムの開発が進み、将来的に`beta` 版パッケージと`latest` パッケージの両方を公開したいと思う時があるかもしれません。
その場合にはnpm tag 機能を使用します。
この機能を使えば、例えば一般のエンドユーザには安定且つ比較的新しいパッケージをインストールさせ、一方で一部のエンドユーザには安定はしていないが最新のバージョン(beta版)を利用させるといった公開方針にすることができます。

今回使用したパッケージを例に`v1.0.1` を`latest` として、`v2.0.0` を`beta` として公開したい場合は次のようにコマンドを実行します。


```console:npmdist-tag
$ npm dist-tag add rpncc@1.0.1 --tag=latest
$ npm dist-tag add rpncc@2.0.0 --tag=beta
$ npm dist-tag ls
```


上記のようにtag 付けを行った結果、エンドユーザ側は普通に`npm install` コマンドを実行すると`latest` なパッケージがインストールされ、`beta` タグを指定して`npm install` した場合は`beta` なパッケージがインストールされるようになります。


```console:npminstallコマンドと、インストールされるバージョンの違いの例
$ npm install rpncc
    -> v1.0.1 がインストールされる
$ npm install rpncc@beta
    -> v2.0.0 がインストールされる
$ npm install rpncc@latest
    -> v1.0.1 がインストールされる
```


# 参考 

- Publishing npm packages
    - https://docs.npmjs.com/getting-started/publishing-npm-packages

- Getting Started with NPM (as a developer)
    - https://gist.github.com/coolaj86/1318304

- Travis CIを使ってみた GitHubのレポジトリにバッジを貼りたかったから
    - http://rcmdnk.github.io/blog/2014/09/08/computer-github-travis/

- Gemnasiumを試してみる
    - http://rochefort.hatenablog.com/entry/2013/04/24/004517

- npmのあまり知られてない機能 10選
    - http://yosuke-furukawa.hatenablog.com/entry/2014/06/10/100410

- Creating and Publishing a Node.js Module
    - https://quickleft.com/blog/creating-and-publishing-a-node-js-module/

- package.json - Specifics of npm's package.json handling
    - https://docs.npmjs.com/files/package.json

- What's the difference between dependencies, devDependencies and peerDependencies in npm package.json file?
    - http://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies

- How to compare arrays in JavaScript?
    - http://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript

- 自作ソースコードに、MITライセンスを適用する３つのやり方
    - http://www.catch.jp/oss-license/2013/09/27/mit_license/