3時間でできるnpmモジュール

[「3分でできるnpmモジュール」](http://qiita.com/fnobi/items/f6b1574fb9f4518ed520)に、公開のための手順がまとめられていて分かりやすかったので(感謝)、実際に3時間で[モジュール](https://www.npmjs.org/package/gulp-phantom)を作ってみました。そのときにやったことのメモ。

(ちなみに、作ったのはPhantomJSをgulpから使いやすくするプラグイン[gulp-phantom](https://www.npmjs.org/package/gulp-phantom)です。よかったら使ってください〜)


## なにするの?

- モジュールのお膳立て
- 実装
- GitHubにソースコードを置く
- [npm](https://www.npmjs.org/)に公開する


## 1時間目

まずはお膳立てから。最低限、必要なファイルはこのあたりです。1時間目に、太字のファイルからやっつけます。

- **package.json**
- **.npmignore**
- **.gitignore**
- **.travis.yml**
- index.js
- test/
- LICENSE
- README.md

### package.json

こんな感じのやつですね。公開しないプロジェクトだと、`dependencies`以外、省略しているケースもあると思いますが、npmに上げる場合は、一通り記載しておきます。

```package.json
{
  "name": "gulp-phantom",
  "description": "phantomjs plugin for gulp",
  "version": "0.0.1",
  "homepage": "https://github.com/cognitom/gulp-phantom",
  "main": "./index.js",
  ...
}
```

モジュールのルートフォルダに移動して、

```bash
$ npm init
```

とやると色々質問されるので、それに答えていくと package.json が作られます。適当に答えておいて、後で直せばOK。

[仕様はここ](https://www.npmjs.org/doc/json.html)にまとめられていますが、設定ファイルの例を見ながら説明してくれる[インタラクティブ ガイド](http://package.json.nodejitsu.com/)が分かりやすいです。

以下、重要なところだけメモ。他は類推でいけると思います。

- `name` モジュール名 (アルファベットとハイフンが使えます)
- `version` とりあえず 0.0.1 (npmに上げるときには都度変更)
- `main` モジュールが最初に読みにいくファイル (`index.js`としました)
- `dependencies` 依存モジュール
- `devDependencies` 開発時のみ使うモジュール
- `scripts` テスト用のスクリプトを指定 (後述)
- `engines` nodeのバージョン指定


#### 注・ハマりかけたところ

他のモジュールを参考にしようと思って、node_modulesにインストールされたものを見ると、 package.json にやたらいろいろ書いています。が、下記のものは手入力しなくてOKです。npmコマンドが勝手に補完してくれるので、気にせずスルーしましょう。

- `readme`
- `readmeFilename`
- `bugs`
- `_id`
- `_from`


### .npmignore

必ずしも必要はありませんが、`tmp/`ディレクトリを外したいとかいった場合に指定します。

```.npmignore
tmp
```

なお、

- `.DS_Store`
- `.git`
- `npm-debug.log`
- `node_modules`

あたりは、[デフォルトで外される](https://www.npmjs.org/doc/misc/npm-developers.html#Keeping-files-out-of-your-package)ので、いちいち書かなくてOKです。

### .gitignore

npmの話というよりもgit一般の話ですが、.npignore に合わせてこちらも設定しておきます。

```.gitignore
.DS_Store
npm-debug.log
node_modules

tmp
```

### .travis.yml

[Travis CI](https://travis-ci.org/)は、GitHubにプッシュすると自動的にテストをかけてくれるサービスです。.travis.ymlがその設定ファイルにあたります。テストを書くのは後半に回しますが、とりあえずこれだけ書きます。GitHubに上がっているリポジトリだと、ほぼ必ず ![Build Status](https://travis-ci.org/cognitom/gulp-phantom.svg?branch=master) みたいのがついてますが、テストをパスしているとこれが緑(passing)になっていて、カッコイイ...もとい安心感があります。

```.travis.yml
language: node_js
node_js:
  - 0.10
```


## 2時間目

いよいよ、実装です。index.jsにガシガシ書いていきます。合わせて、テストをtestディレクトリに作っていきます。

- **index.js**
- **test/**


### index.js

よくあるパターンは、こんな感じです。必要なモジュールを`require`して、`module.exports`の中に実際のコードを書いていきます。実装についての詳細は、ここでは略。

```
var spawn = require('child_process').spawn,
    through = require('through2'),
    gutil = require('gulp-util'),

module.exports = function(options){
  ...
}
```

### テスト・テスト・テスト

今回は、[mocha](http://visionmedia.github.io/mocha/)を使いました。

testディレクトリの構成はこんな感じ。

- expect/
	- test1.txt
	- test2.txt
- fixtures/
	- test1.js
	- test2.js
- main.js (あるいは、main.coffee)

main.jsというか、main.coffeeにテストを書き書き。

```main.coffee
should = require 'should'
phantom = require '../'

describe 'gulp-phantom', () ->
  describe 'phantom()', () ->
    it 'should pass file when it isNull()', (done) ->
      ...
    it 'should emit error when file isStream()', (done) ->
      ...
    it 'should trim newline at EOF', (done) ->
      ...
```

テストがだいたい書けたら、package.jsonにテストスクリプトを指定しておきます。

```package.json
{
  "scripts": {
    "test": "mocha -R spec"
  }
}
```

ちなみに、テストをCoffeeScriptで書く場合は、`--compilers`と`--require`の指定が必要です。

```package.json
{
  "scripts": {
    "test": "mocha --compilers coffee:coffee-script --require coffee-script/register -R spec"
  }
}
```

これで、下記のコマンドでテストが実行できるようになります。Travis CIもこの設定を認識してくれます。

```bash
$ npm test
```

#### 注・ハマりかけたところ

実は、この段階ではテストが通ったのですが、Travis CIで引っかかりました (泣)。mochaのタイムアウトだったので、`describe` のところでタイムアウト値を多めに設定して、事無きを得ました。

```main.coffee
describe 'gulp-phantom', () ->
  describe 'phantom()', () ->
    @timeout 10000
```


## 3時間目

テストを含めて実装ができたら、READMEやLICENSEを用意して、GitHubに公開する準備をします。

- **LICENSE**
- **README.md**

この2ファイルを用意したら、

- GitHubに公開
- Travis CIを設定
- npmに公開

で、完成!


### LICENSE

MITライセンスにしたので、こんな内容を入れておきます。[全文はここ](http://opensource.org/licenses/MIT)にあるので、コピーしてきて、年と名前を差し替えればOK。

> The MIT License (MIT)
> 
> Copyright (c) 2014 Tsutomu Kawamura
> 
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, ...(略)


### README.md

```README.md
# gulp-phantom

A PhantomJS plugin for [gulp](https://github.com/wearefractal/gulp).

(略)
```

### GitHubに公開

新しいリポジトリを作って、そこにソースコードをプッシュします。今回用意したのは[こちら](https://github.com/cognitom/gulp-phantom)。

- https://github.com/cognitom/gulp-phantom


### Travis CIを設定

アカウントを作っていない場合は、[Travis CI](https://travis-ci.org/)にGitHubアカウントを使ってサインアップします。自動的に自分のリポジトリがリストアップされるので、該当するもののスイッチをONにします。作業としては本当にこれだけ。

TravisはGitHubにプッシュされたことをフックにして、自動実行されるので、README.md にビルドバッジ ![Build Status](https://travis-ci.org/cognitom/gulp-phantom.svg?branch=master) を足してプッシュしてみます。

```README.md
# gulp-phantom [![Build Status](https://travis-ci.org/cognitom/gulp-phantom.svg?branch=master)](https://travis-ci.org/cognitom/gulp-phantom)

A PhantomJS plugin for [gulp](https://github.com/wearefractal/gulp).

(略)
```

しばらくすると、テストが始まります。「passing」になればOK!


### npmに公開

ここからは、あと「3分」です。ぜひ、[fnobi](http://qiita.com/fnobi)さんによる[「3分でできるnpmモジュール」](http://qiita.com/fnobi/items/f6b1574fb9f4518ed520)をどうぞ。

概略としては、[サインアップ](https://npmjs.org/signup)して、

```bash
$ npm adduser
```

それから、モジュールのフォルダで`npm publish`すればOK。

```bash
$ npm publish
```

あとは、別プロジェクトから、`npm install <モジュール名>`できるかチェックしておきましょう。


## 放課後

本筋から離れるものの、関連する話題をメモ。

### npmで公開しないシャイなモジュール

いきなりnpmに公開するのは、ちょっと抵抗があったり、なかったり。npmでは、ローカルで開発中のモジュールも、ファイルパスを指定すればインストールできます。ただ、この方法だと`--save-dev`できません。

```bash
$ npm install /path/to/dir
```

GitHub上に公開する必要がありますが、gitのURLを指定することもできます。この場合は`--save-dev`が使えます。

```bash
$ npm install git://github.com/cognitom/gulp-phantom.git --save-dev
```

package.json に直接書く場合はこんな感じ。詳しくは、[npm-installのドキュメント](https://www.npmjs.org/doc/cli/npm-install.html)をどうぞ。

```
{
  "devDependencies": {
    "gulp": "*",
    "gulp-phantom": "git://github.com/cognitom/gulp-phantom.git"
  }
}
```


## 参考

- [Developer Guide](https://www.npmjs.org/doc/misc/npm-developers.html)