3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

npmでReactのComponentを公開する

Last updated at Posted at 2015-08-28

この記事なに?

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

対象ユーザー

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

(参考資料)npmについての基本的な知識や、パッケージの公開方法

フロントエンド開発の3ステップ(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

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'));
});

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はこんなかんじです。

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の内容ではないと思います。

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

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?