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

この記事は クソアプリ Advent Calendar 2018 の第5日目の記事です。

↑にしたかったのですが、遅刻してしまったので ゆめみ Advent Calendar 2018 の第9日目の記事になります!ついでに言うと、こちらでも遅刻です🙇‍♀️


はじめに

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

「Create npm module and publish to npm」

Node.jsいくつかお遊びのモジュールを作ってアップしてますので、よろしければダウンロードしてご意見いただけると嬉しいです!


作ったもの

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

ezgif-5-e929e034efcf.gif

URL: https://www.npmjs.com/package/ja-greetings

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

オプションとしては、

  * 方言:広島弁、沖縄弁、京都弁、大阪弁

  * 言語:英語、中国語

  * 囲い:なし、☆、★、*、▽△、▼▲、/ ̄_/

を用意しました。方言はそろそろ追加が厳しく、地方の人のレビューがいただきたいです :bow:

また生まれて初めて自分でコマンドを作り、全世界に公開したのですが、割と簡単に作れた事により味をしめてしまい、これ以降もいくつか作っては npm にアップする趣味ができましたw

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


使い方

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



$ npm i -g ja-greetings

# ヘルプを表示
$ jgr -h

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

☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆

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


☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆


まぁざっくりこんな感じです。後は help や README を見ていただければわかると思いますー😁


なぜCLIを?

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


  • 私がCUIが好き

  • モジュールを扱うNode.jsとの親和性が高い

  • OSS として始めやすい


諸々の知見


npm への公開方法

npm にアップするやり方は物凄く簡単でした👍たったの3ステップです!


1. 自分のターミナルからnpmにログイン

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


コマンド


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


2. package.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 についてはこちらのページがまとまっていてとても参考になります。


3. 公開

たった1コマンドを実行するだけです。


コマンド

$ 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 というモジュールをインストールします。

$ npm i node-alias

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

$ cp bin/ja-greetings bin/jgr

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

#!/usr/bin/env node

require('node-alias')('jgr', __dirname)

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

$ 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

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

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

hoge.png


注意事項

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


1. メンテナンスをしないなら削除する

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


  • 他の人が同じ名前でモジュールをアップロードしたくてもできない

  • 雑音が増えるので、 npm の検索性が下がる


○例1:

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

$ 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 ってなんだ…? と言うことは他にもあるのか?)

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

$ 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 で同じ名前がないか調べてみます。

$ npm s hoge

NAME | DESCRIPTION | AUTHOR | DATE | VERSION | KEYWORDS
hoge | test | =hoge | 2015-08-08 | 0.0.1 |

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

$ 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 ってあからさまに適当に作ったモジュールじゃないか?これ他にもあるんじゃ…)

$ 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」

では(=゚ω゚)ノ