npmでReactのComponentを公開する

#この記事なに？
最近Reactを使って動くものが作れるようになった！という人向けに、もう一歩踏み込んで作ったコンポーネントをnpmで公開するための方法を共有したいと思います。

##対象ユーザー
- 最近Reactを使って動くものが作れるようになった！という人
- gulpはなんとなくだけど使える
- npmでパッケージを公開したことがない人
- 作ったコンポーネントを見せつけてドヤリングしたい人

##(参考資料)npmについての基本的な知識や、パッケージの公開方法
フロントエンド開発の３ステップ（npmことはじめ）
http://qiita.com/hashrock/items/15f4a4961183cfbb2658

3分でできるnpmモジュール
http://qiita.com/fnobi/items/f6b1574fb9f4518ed520

3時間でできるnpmモジュール
http://qiita.com/cognitom/items/75736e27cc7de151a7d5



##やったこと

まずはじめに、上記の参考文献で書いてあるようにnpmのユーザー登録を行っておいてください。
これがないとnpmに登録することができません。登録ができたらコマンドラインで`npm adduser`するのも忘れないでください。


続いてsrcに配置したjsxをjsにコンパイルし、gulpを使ってビルドします。
それぞれのソースファイルはこちら。

まずはこのgulpfileでjsxをjsにコンパイルします。
コンパイルするjsxも載せておきますが本当にただのjsxです。

`$ gulp`

```lang:gulpfile.js
'use strict';

var gulp = require('gulp'),
      react = require('gulp-react'),
      concat = require('gulp-concat'),
      sass = require('gulp-sass'),
      plumber = require('gulp-plumber');

gulp.task('compile:scss', function() {
  gulp.src('./css/*.scss')
         .pipe(plumber())
         .pipe(sass())
         .pipe(concat('index-filter.css'))
         .pipe(gulp.dest('./css'))
});

gulp.task('default', function () {
    return gulp.src('./src/index-filter.jsx')
        .pipe(react({
            harmony: true
        }))
        .pipe(concat('index.js'))
        .pipe(gulp.dest('./lib'));
});

```





```lang:index-fiter.jsx
'use strict';

var React = require('react'),
      FontAwesome = require('react-fontawesome');

var FilterItem = React.createClass({
  getInitialState: function() {
    return {
      isMouseOver: false
    }
  },

  toggleChecked: function() {
    this.props.toggleChecked(this.props);
  },

  setIconVisibility: function() {
    if (this.props.hasChecked === true) {
      return ''
    } else {
      return 'index-filter_invisible'
    }
  },

  setTextColor: function() {
    if (this.props.hasChecked === true) {
      return 'index-filter_checked'
    } else {
      return ''
    }
  },

  toggleIconStyle: function() {
    this.setState({ isMouseOver: !this.state.isMouseOver})
  },

  getIconStyle: function() {
    if (this.state.isMouseOver === true) {
      return 'times-circle';
    } else {
      return 'check';
    }
  },

  render: function() {
    return(
      <li className={"index-filter__item-wrapper " + this.setTextColor()}>
          <div className="index-filter__item ui-checkbox" onClick={this.toggleChecked} onMouseOver={this.toggleIconStyle} onMouseOut={this.toggleIconStyle} >
              <div className="index-filter__image-wrapper"><img className="index-filter__image" src={this.props.iconUrl} /></div>
              <div className="index-filter__label">{this.props.id}</div>
              <FontAwesome className={"index-filter__check-icon " + this.setIconVisibility() } name={this.getIconStyle()} size='lg' />
          </div>
      </li>
    )
  }
});

var IndexFilter = React.createClass({
  getInitialState: function() {
    return {
      options: this.props.options,
      isRevealed: true
    }
  },

  toggleFilterOption: function(){
    this.setState({
      isRevealed: !this.state.isRevealed
    });
  },

  toggleChecked: function(selectedOption) {
    var options = this.state.options
      .filter(function(option) {
        return option.id === selectedOption.id;
      })
      .map(function(option){
        return option.hasChecked = !option.hasChecked;
      })

    this.setState({ options: this.state.options });
  },

  render: function() {
    var rows = [];
    this.state.options.forEach(function(option) {
      rows.push(
        <FilterItem key={option.id} id={option.id} iconUrl={option.iconUrl} hasChecked={option.hasChecked} toggleChecked={this.toggleChecked} />
      )
    }.bind(this));

    return(
      <div className="index-filter">
          <h5 className="index-filter__header" onClick={this.toggleFilterOption} >{this.props.title}<FontAwesome name="chevron-down" rotate={ this.state.isRevealed ? "180" : null } size='lg' /></h5>
          <ul className={"index-filter__item-list " + (this.state.isRevealed ? 'index-filter_revealed' : '')}>
              {rows}
          </ul>
      </div>
    );
  }
})

module.exports = IndexFilter;
```

そのあとはpackage.jsonを修正します。
重要なのはmain と keywordsです。
mainには先ほどコンパイルして配置したlib/index.jsを指定しないと動きません。
keywordsにはreact-componentと入れておくと、
react-components.comというサイトからの検索に引っかかるので、こちらも記入するようにしてください。

（参考）React Components
      http://react-components.com/

ちなみに自分のpackage.jsonはこんなかんじです。

```lang:package.json
{
  "name": "react-index-filter",
  "version": "0.1.0",
  "description": "",
  "keywords": "react-component",
  "main": "lib/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "takayuki-ochiai",
  "license": "ISC",
  "dependencies": {
    "font-awesome": "^4.4.0",
    "react": "^0.13.3",
    "react-fontawesome": "^0.2.5"
  },
  "devDependencies": {
    "babelify": "^6.2.0",
    "browser-sync": "^2.8.2",
    "browserify": "^11.0.1",
    "gulp": "^3.9.0",
    "gulp-concat": "^2.6.0",
    "gulp-plumber": "^1.0.1",
    "gulp-react": "^3.0.1",
    "gulp-sass": "^2.0.4",
    "vinyl-source-stream": "^1.1.0",
    "watchify": "^3.3.1"
  }
}
```

package.jsonを記入したらあとはコマンド一発です。

`$ npm publish`

おめでとうございます！これでコンポーネントの公開は終了です！
あとはできればgithubにソースコードをプッシュしたりREADMEを充実させたりしてみてください！

##最後に
自分も先日初めてnpmにパッケージを公開したばかりなので、この記事の内容はBestの内容ではないと思います。

もし明らかな間違いがあったり、よりよい方法がある、という場合はご指摘いただけるとありがたいです。