hyperappでコンポーネント単位でファイルを分割してみる

# hyperappとは
[ここ](http://qiita.com/jbucaran/items/ac7d54d862dcb33673f1)に作者の@jbucaranさんの記事があるので、そちらをご覧あれ。

# この記事は？
最近hyperappを使って作っているものがあって、それ用の備忘録です。
\# 当然、人目に晒すことで、いろいろアドバイスをもらおうって魂胆も

# 本題
## 悩み
hyperappでコンポーネントごとにファイルを分けるには、どう書いてどう読み込めばいいか。
[あるissue](https://github.com/hyperapp/hyperapp/issues/8)内のコメントや[forkされたリポジトリ](https://github.com/nichoth/hyperapp/tree/master/examples)に、コンポーネントごとに分ける例はあった。

ただこれもindex.jsのような単一のファイルに全て書かれていて、コンポーネントごとに更新していくのがツラいかもと思い、ファイル分割を色々試行錯誤してみた。

もっといいやり方をご存知の方はコメントください。

## お題
分割のお題はCodePen上の[サンプル](https://codepen.io/hyperapp/pen/PWXNPO?editors=0010)。下記のような１ファイルのjsx。

```js:index.jsx
const { h, app } = hyperapp
/** @jsx h */

const Slider = ({ color, value, update }) =>
  <div>
    <input
      type="range" min="0" max="255"
      value={value}
      oninput={e => update({
        color: color,
        value: e.target.value
      })}
    />
  </div>

app({
  state: { red: 255, green: 255, blue: 255 },
  actions: {
    changeColor: (state, actions, { color, value }) => ({ [color]: value }),
    updateBgColor: (state, actions, data) => {
      document.body.style.backgroundColor = `rgb(${state.red}, ${state.green}, ${state.blue})`
      actions.changeColor(data)
    }
  },
  view: (state, actions) =>
    <div>
      <p>Use the sliders to change the background color.</p>
      {Object.keys(state).map(color =>
        <Slider
          color={color}
          value={state[color]}
          update={actions.updateBgColor}
        />)}
    </div>
})
```
これを思いのままに分割してみる。
## 結果
以下のようなファイル構成に分割してみた。

```shell-session:
src/js
├── components
│   ├── slider.js
│   └── sliderList.js
└── index.js
```

それぞれのファイルの中身は下記に。

```js:index.jsx
import { h, app } from 'hyperapp';
import SliderList from './components/sliderList';
/** @jsx h */

app({
  state: { red: 255, green: 255, blue: 255 },
  actions: {
    changeColor: (state, actions, { color, value }) => ({ [color]: value }),
    updateBgColor: (state, actions, data) => {
      document.body.style.backgroundColor = `rgb(${state.red}, ${state.green}, ${state.blue})`
      actions.changeColor(data)
    }
  },
  view: (state, actions) =>
    <SliderList
      colorValues={state}
      update={actions.updateBgColor}
    />
})
```

```js:sliderList.js
import { h } from 'hyperapp';
import Slider from './slider';

export default ({ colorValues, update }) =>
  <div>
      <p>Use the sliders to change the background color.</p>
      {Object.keys(colorValues).map(color =>
        <Slider
          color={color}
          value={colorValues[color]}
          update={update}
        />)}
    />
  </div>
```

```js:slider.jsx
import { h } from 'hyperapp';

export default const ({ color, value, update }) =>
  <div>
    <input
      type="range" min="0" max="255"
      value={value}
      oninput={e => update({
        color: color,
        value: e.target.value
      })}
    />
  </div>
```

ビルドはgulp&browserifyで。こちらもアドバイス＆突っ込みが欲しい。

```js:gulpfile.js
var gulp = require("gulp");
var babel = require("gulp-babel");
var uglify = require('gulp-uglify');
var babelify = require('babelify');
var transform = require('vinyl-transform');
var source = require('vinyl-source-stream');
var buffer = require("vinyl-buffer");
var browserify = require('browserify');
var collapse = require('bundle-collapser/plugin');

/*
 * （中略）
 */

gulp.task( 'browserify', function() {
  return browserify('./src/js/index.js', { debug: false })
    .transform(
      babelify,
      {
        presets: ["es2015"],
        plugins: [
          [
            "transform-react-jsx",
            {
              "pragma": "h"
            }
          ]
        ]
      }
    )
    .plugin(collapse)
    .bundle()
    .on("error", function (err) { console.log("Error : " + err.message); })
    .pipe(source('dist/js/bundle.js'))
    .pipe(buffer())
    .pipe(uglify())
    .pipe(gulp.dest('./'))
});
```