nodejsの勉強のために、明日役に立たないCLIアプリを作ったときの知見をまとめる

~~この記事は [クソアプリ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/kuso-app) の第5日目の記事です。~~

↑にしたかったのですが、遅刻してしまったので [ゆめみ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/yumemi) の第9日目の記事になります！ついでに言うと、こちらでも遅刻です🙇‍♀️

# はじめに

本記事は、こちらのスライドの具体例を用いたお話ですが、主に自分の備忘録として書いたものですので、ご存知の方も多いと思います。

[「Create npm module and publish to npm」](https://speakerdeck.com/clown0082/create-npm-module-and-publish-to-npm)

`Node.js` で[いくつかお遊びのモジュールを作ってアップ](https://www.npmjs.com/~k-kuwahara)してますので、よろしければダウンロードしてご意見いただけると嬉しいです！

# 作ったもの

本記事では、作ったものの中の１つ `ja-greetings` という CLI アプリケーションについて触れていきます。どんなアプリケーションかは、以下をご覧ください。

![ezgif-5-e929e034efcf.gif](https://qiita-image-store.s3.amazonaws.com/0/48034/c13cc303-ed1f-57e8-281f-a8b2c41cc462.gif)
URL: https://www.npmjs.com/package/ja-greetings

一言で言うと、__日本の各種挨拶をコマンドラインに表示する__、というアプリケーションです。具体的には、「新年」「暑中お見舞い」「寒中お見舞い」「年末」「感謝」「謝罪」の6つです。

オプションとしては、

　　* 方言：`広島弁、沖縄弁、京都弁、大阪弁`
　　* 言語：`英語、中国語`
　　* 囲い：`なし、☆、★、＊、▽△、▼▲、/￣＿/`


を用意しました。方言はそろそろ追加が厳しく、地方の人のレビューがいただきたいです :bow: 
また生まれて初めて自分でコマンドを作り、全世界に公開したのですが、割と簡単に作れた事により味をしめてしまい、これ以降もいくつか作っては `npm` にアップする趣味ができましたw

ちなみに、このアプリケーションの GitHub リポジトリも面談時に見せましたが、多分自分の実力感も伝えられたので、タイトルの`明日役に立たない`は間違いですね(；・∀・)

# 使い方
（↑で載せた動画と同じですが）Node.js の version 8 以上がインストールされている環境でターミナルを開き、以下のコマンドを実行。

```shell:例
$ npm i -g ja-greetings

# ヘルプを表示
$ jgr -h

# 新年のあいさつを広島弁で白星で囲んで表示
$ jgr new -d hiroshima -s w-star


☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
            あ
      今  おけ
    よ年  めま
    ろも  でし
    し    とて
  おゅ    う
  願う  ご
  い    ざ
  す    い
  る    ま
  ん    す
  じ    け
  ゃ    ぇ
  け    の
  ぇ    。
  の
  。
☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
```

まぁざっくりこんな感じです。後は help や [README](https://github.com/k-kuwahara/ja-greetings/blob/master/README.md) を見ていただければわかると思いますー😁


# なぜCLIを？
これはたまに聞かれるのですが、だいたい以下の理由になりますが、学習の意味でも本当に適していると思います。純粋にプログラミングや Node.js の勉強になりました。

* 私が`CUI`が好き
* モジュールを扱うNode.jsとの親和性が高い
* OSS として始めやすい

# 諸々の知見

## npm への公開方法
npm にアップするやり方は物凄く簡単でした👍たったの3ステップです！


### 1. 自分のターミナルからnpmにログイン
npm への公開もターミナルから行いますので、先にログインをしておきます。

```shell:コマンド

$ npm login
Username: k-kuwahara
Password:
Email: (this IS public)
```

### 2. package.json を整備
完璧に書く必要はないですが、個人的にこの項目は書くよね、というものをピックアップしました。必須項目も含みます。

```json
{
  "name": "ja-greetings", // 名前
  "version": "1.5.8", // バージョン
  "description": "ja-greetings is a cli tool that displays Japanese greetings",　 // このアプリケーションの簡単な説明
  "license": "MIT", // ライセンス。 OSS で困ったら MIT でおk
  "main": "./lib/ja-greetings.js", // このアプリケーションのコアとなるファイル
  "bin": {
    "ja-greetings": "./bin/ja-greetings",
    "jgr": "./bin/jgr"
  }, // このアプリケーションのコマンド（今回は `jgr, ja-greetings` の2つ）
  "keywords": [
    "ja-greetings",
    "greetings",
    "cli-app"
  ], // npm で検索したときのヒット率に関わってくる
  "engines": {
    "node": ">=8.0"
  }, // Node.js の動作環境
  "author": {
    "name": "k-kuwahara",
    "email": "zensin0082@gmail.com"
  }, // 開発者（複数人なら全員書く）
  "repository": {
    "type": "git",
    "url": "k-kuwahara/ja-greetings"
  }, // このアプリケーションのソースのリポジトリ情報
  "homepage": "https://github.com/k-kuwahara/check-stats-modules#readme" // なければREADME
}
```

`package.json` については[こちらのページ](http://liberty-technology.biz/PublicItems/npm/package.json.html)がまとまっていてとても参考になります。

### __3. 公開__
たった1コマンドを実行するだけです。

```shell:コマンド
$ npm publish

# うまくいけば
npm notice
npm notice 📦  ja-greetings@1.5.9
npm notice === Tarball Contents ===
npm notice 770B  package.json
npm notice 1.1kB LICENSE
npm notice 2.1kB README.md
npm notice 60B   bin/ja-greetings
npm notice 1.7kB bin/jgr
npm notice 1.4kB greetings/last.gr
npm notice 1.2kB greetings/new.gr
npm notice 386B  greetings/sorry.gr
npm notice 695B  greetings/summer.gr
npm notice 339B  greetings/thx.gr
npm notice 692B  greetings/winter.gr
npm notice 388B  lib/app.js
npm notice 2.3kB lib/format.js
npm notice 1.6kB lib/greetings.js
npm notice 1.9kB lib/ja-greetings.js
npm notice === Tarball Details ===
npm notice name:          ja-greetings
npm notice version:       1.5.9
npm notice package size:  5.7 kB
npm notice unpacked size: 16.5 kB
npm notice shasum:        003ba26e487751ba21981e86bb77c6c2683940f1
npm notice integrity:     sha512-IhEDAt+6gGwRS[...]b2vGP23WcssFA==
npm notice total files:   15
npm notice
+ ja-greetings@1.5.9
```

成功すれば、上記のように `name@version`が表示されるとともに、登録しているメールアドレスに成功の旨のメールが飛んでくると思います。

## CLI なら alias を用意しよう

今回作ったモジュールは CLI ですが、`ja-greetings` なんて長いコマンド名を毎回ターミナルに打つのは辛いので、省略したコマンドが欲しくなりますよね。と言うことで、それを用意しましょう。まずは `node-alias` というモジュールをインストールします。

```bash
$ npm i node-alias
```

次に、省略したコマンド用のファイル `bin/jgr` を用意します。

```bash
$ cp bin/ja-greetings bin/jgr
```

最後に、メインのコマンド用アフィル `bin/ja-greetings` を以下のように書き換えてください。

```
#!/usr/bin/env node
require('node-alias')('jgr', __dirname)
```

これで完了です。実際に叩いてみると、エイリアスがあるよ！ と教えてくれるようになります。

```bash
$ npm link
$ ja-greetings -h
[INFO]: You can also use jgr as an alias
Usage:
  ja-greetings <command> [-d prefecture] [-s surround] [-l language]

（以下略）
```

## READMEの装飾

GitHub のいろんなリポジトリをみていると、README のトップにいくつかのバッジが表示されていることがあると思います。（ちなみに、`ja-greetings` のREADMEは以下）

![スクリーンショット 2018-12-25 19.16.27.png](https://qiita-image-store.s3.amazonaws.com/0/48034/c932f491-7f3d-2950-bfa5-b15068646988.png)

これは、リポジトリのダイジェストな情報を伝える意味でもとても有効ですので、ぜひつけたほうが良いかと思います。これらのバッジのリンクや画像を取得先は、[shields.io](https://shields.io/#/) というサイトから取得できます。

自由に文言や色も変更できますので、好きなバッジを作ってみてください👍以下、サンプル。

![hoge.png](https://qiita-image-store.s3.amazonaws.com/0/48034/d405d6a2-c6a9-b0e6-e1c2-afa112c4d2e3.png)

## 注意事項

簡単に公開できるため OSS としてのハードルも比較的低い分、注意すべきこともいくつかありますので、ここに列挙致します。

### __1. メンテナンスをしないなら削除する__

これは主に２つの理由があります。

* 他の人が同じ名前でモジュールをアップロードしたくてもできない
* 雑音が増えるので、 npm の検索性が下がる

#### ○例１:
`json` データをごにょごにょできるライブラリを作ったので、npm にアップすることを考えたとします。このとき、同じ名前のモジュールがないか検索してみますと、このようになります。

```terminal
$ npm s json

NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
json                      | a 'json' command…    | =trentm         | 2017-03-03 | 9.0.6    | json jsontool filter command shell
JSON                      | Douglas Crockford's… | =coolaj86       | 2011-09-08 | 1.0.0    | ender
json5                     | JSON for humans.     | =aseemk…        | 2018-09-28 | 2.1.0    | json json5 es5 es2015 ecmascript
jsonfile                  | Easily read/write…   | =jprichardson…  | 2018-09-08 | 5.0.0    | read write file json fs fs-extra
```

（なるほど。すでにあるようだ…ん？ `json5` ってなんだ…？ と言うことは他にもあるのか？）

と思うわけです。そうすると、やっぱり調べてみたくなるので、調査を続行します。

```terminal
$ npm s json2
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
json2-mod                 | Douglas Crawford's…  | =martindrapeau  | 2018-10-28 | 1.0.4    | json parse stringify json2 crockford
JSON2                     | Douglas Crawford's…  | =ddopson        | 2012-04-16 | 0.1.0    |
2json                     | json flattener that… | =prussian       | 2016-12-02 | 0.2.1    | xml2 json2
json2-2018                | json2.js for node…   | =sbfkcel        | 2018-09-07 | 1.0.0    |
JSON                      | Douglas Crockford's… | =coolaj86       | 2011-09-08 | 1.0.0    | ender
json2                     | json2 / native JSON… | =samuraijack    | prehistoric | 0.4.0    |

$ npm s json3
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
json3                     | A modern JSON…       | =kitcambridge…  | 2014-06-22 | 3.3.2    | json spec ecma es5 lexer parser stringify
d3-hexjson                | Generate hexmaps…    | =olihawkins     | 2017-12-09 | 1.0.1    | d3 d3-module hexjson hexmap
```

と、このように名前が重複していると他の人が使えず、ついつい`既存ライブラリ名 + 数字` という名前にしがちです。もっと良い名前を自分でつければ良いのでしょうが、どうしてもその名前にしたいときもあると思いますので、__有用性がある__のであれば削除せず、遊びであったり勉強用だったならば、なるべく削除していただければと思います。

#### ○例2:

勉強用に `hoge`  モジュールを作ってアップすることを想定してみましょう。上記と同様に npm で同じ名前がないか調べてみます。

```terminal
$ npm s hoge
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
hoge                      | test                 | =hoge           | 2015-08-08 | 0.0.1    |
```

（あちゃー、すでに使われていたかー。じゃあ `fuga` にしてみよう。）

```terminal
$ npm s fuga
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
@fugazi/connector         | basic functionality… | =fugazi-admin   | 2017-12-23 | 1.0.18   |
typeface-fugaz-one        | Fugaz One typeface   | =kylemathews    | 2018-01-24 | 0.0.54   | typeface font font family google fonts fugaz-one
daedalus-fugazi-webclient | web based terminal…  | =amir-arad      | 2017-12-20 | 0.1.0    |
@fugazi/webclient         | web based terminal…  | =fugazi-admin   | 2017-12-06 | 1.1.21   |
fugazi                    | Functional…          | =layv           | 2017-03-24 | 0.5.2    | functional async promise ramda
fugotcha                  | A web scraper for…   | =frago          | 2018-12-08 | 1.0.0    |
@fugazi/connector.mongo   | a fugazi mongodb…    | =creativechips… | 2017-07-28 | 1.0.3    | fugazi mongo cli api rest rpc
@fugazi/connector.ssh     | a fugazi connector…  | =creativechips… | 2017-07-29 | 1.0.1    |
@fugazi/proxify           | a fugazi proxy to…   | =creativechips… | 2017-06-26 | 1.0.1    | fugazi proxy cross origin api rest rpc
@fugazi/connector.redis   | a fugazi redis…      | =fugazi-admin   | 2017-07-04 | 1.0.5    | fugazi redis cli api rest rpc
```

（おっ。幸いにも `fuga` は使われていなかったので大丈夫だ…ちょっと待て。`hoge` ってあからさまに適当に作ったモジュールじゃないか？これ他にもあるんじゃ…）

```terminal
$ npm s piyo
No matches found for "piyo"

$ npm s aaa
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
aaa                       | aaa...               | =erhu65         | 2012-12-31 | 0.0.2    | math

$ npm s eee
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
eeeee                     |                      | =o_0            | 2018-12-18 | 0.0.0    |

$ npm s bar
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
bar                       | Node.js framework…   | =fedor.indutny  | 2013-02-10 | 0.1.2    |
```

このように色々調べると、あからさまにテキトーに作ったものや、全然メンテナンスしてないものが多く、検索する際にこれらも含めて npm は検索しに行きますので、ぜひ削除していただきたいです。

また検索結果のテーブルに表示されると、見辛くもなりますので、たとえ勉強中だとしても、区切りがついたらそのタイミングで削除をお願いします。


### __2. しっかりテストを書く__

こちらにも理由があります。

* 自作モジュールの信頼性向上
* セキュリティの観点から
* Node.js のバージョンにより発生する不具合検知のため

npm は OSS のためのプラットフォームですので、簡単に悪意のあるソースコードを含めたモジュールをアップロードできてしまいますし、npm そのものにも不具合や危険なコードが含まれる可能性は多いにあり得ます。

したがって、自分の作ったモジュールの検証をするためにも、テストはなるべく書いていきましょう！（自戒の意味も込めて）


# 終わりに

今回は具体的なサンプルアプリを用意しましたが、コードの説明については実際にソースコードを読んでいただければと思います。全然複雑な構成にはなっておりませんので、文字通り読めば分かるかと思います。（設計的にも美しいとは言えず、愚直に作っております :bow: ）

いろいろ書きましたが、ダイジェストで見たい場合は、（手前味噌ですが）こちらのスライドにまとめてますので、こちらも見ていただければ嬉しいです！

[「Tips for OSS」](https://speakerdeck.com/clown0082/tips-for-oss)

では(=ﾟωﾟ)ﾉ