|> Weeeeeeb

どんどんドーナツどーんと行こう!(10万円山さん)

Day.2 BABELがバージョン6系になって盛大にはまった件

もはやAdventCalendarやってませんね。。。
11月後半から鬱状態で休日は用事がない時はずっと家で寝ていました。

そんな時に、業務中に面白そうなアプリ案を思いついて
electron + React + (Redux ?) で実装してみようと思い

何も考えず、npm initでプロジェクト作成。
JavaScriptなのだからes6を使いたいのでbabelgulpを追加

ここまでは問題なくいつもどおりだった。。。

そして問題は起こった

  • babelのバージョンが6系だった

JavaScriptをes6で書いていって、gulpでタスク追加して
いざテストとして、タスク実行している時に事件は起きた。

es6で書いたJavaScriptコンパイルされない!!

訳が分からずテストコードを書いてみて、CLIからコンパイルしてみるが
結果は変わらず。。。

$ babel test.js
class Person {
    constructor() {
        this.name = "arukmn";
    }
}

const obj = (() => {
    return {
        log() {
            alert('Hello Babel!');
        }
    };
})();

やっぱりわけがわからない私は相談してみることに。

解決編

調べてみるとbabelのバージョン6について下記のようなことが判明した。

  • 全体的に色々と修正が加えられていること
  • Reactなどを使用する際はpresetsを指定しなければならない
  • presetsbabelとは別にインストールする必要がある
  • presets.babelrcという設定ファイルに記述しなければならない

ということで、上記の変更点を反映させました。

  1. 必要なpresetsnpm i -S
  2. package.jsonと同一階層に.babelrcを作成
  3. presetsの設定を記述

私は今回、下記のpresetsをインストールしました。

Presets Package
es2015 babel-preset-es2015
stage-0 babel-preset-stage-0
React babel-preset-react

全ての工程が完了後、再度テストをかけると正常にコンパイルされました。

$ babel src/test.js

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Person = function Person() {
 _classCallCheck(this, Person);

 this.name = "arukmn";
};

var obj = (function () {
 return {
   log: function method() {
     alert('Hello Babel!');
   }
 };
})();

さいご

技術的情報は逐次チェックする事、分かっていたことですが
今あるものがずっと続く訳がない事を再確認しました。

最近はJavaScriptを書けていなかったこともあり
いつもes5を使っていたことも仇になってしまったかもしれません。

さいごに、

コンパイル遅せぇぇ

なんで?なんで?

  • [✔] コンパイルがクソ遅い原因が何なのか調査してみる

babeljs.io

Day.1 Flux入門

React.jsは以前触っていましたが、Fluxのアーキテクチャについては不勉強だったため、
この機会に入門してみる。

まずはということで簡単なアプリを作ります。
今回勉強のために使わせていただいたのは下記のスライド↓(ありがとうございます)

10分で実装するFlux

私の方でもほぼ同一のものを作成しました。

github.com

アーキテクチャ

Fluxのアーキテクチャです。
React.jsだけを勉強していた私でも見たことがある有名な図ですね。
図から自明ですが、データの流れが一方向になっています。(Angularとかは双方向でしたよね)

https://facebook.github.io/react/img/blog/flux-diagram.png

Component

Viewですね。ここでAction(イベント)を呼び出します。
Store(state)が更新されたタイミングでViewが更新されます。
ユーザーは更新を意識する必要はありません。

Action

ここでは、システム的なイベントやユーザー入力(onClick等)等の管理を行います。
この後、Dispatcherへデータを渡します。
その他外部(API)との通信等も行います。

Dispatcher

DispatcherはFluxで提供されているモジュール。
Fluxの中ではコアな部分?
ここで、事前にStoreに登録されているコールバックを呼び出す。

本来はEventEmitterを内包しているのがDispatcherで、
EventEmitterの制御を行っているとのこと。

私自身EventEmitterは全然知らなくて、参考にしている記事からの情報しか知らないので
AdventCalendarのどこかで取り上げたい…

Store

Storeは基本的にデータの管理(state)を行います。
また、ビジネスロジックを記述する部分です。

またはStoreはSetterを持たず、コールバックにて、値の代入などを行います。(Getterはある)

処理に関して

私の理解で記述したファイルの処理を書きます。
自分のためなんじゃ…

※下記にプログラムを掲載しますが、参考記事様のコードとほぼほぼ同一なので
そちらを参照した方がよいかもしれません。

Component -> (Component.js)

今回作成したのは簡単なカウンターなので、
必要なViewは下記の2点のみです。

  • カウントするボタン
  • カウントを表示するラベル

constructor

  • stateの初期値をStoreから取得
  • Storeからのコールバックを登録(このタイミングで再描画)

tickメソッド

  • Actionの呼び出し
"use strict";
import React from "react"
import ActionCreator from "./ActionCreator"
import Store from "./Store"
import EventEmitter from "./EventEmitter"

var dispatcher = new EventEmitter();
var action = new ActionCreator(dispatcher);
var store = new Store(dispatcher);

export default class Component extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: store.getCount() };
        // Observe store's change
        store.on("CHANGE", () => {
            this._onChange();
        });
    }
    _onChange() {
        this.setState({ count: store.getCount() });
    }
    tick() {
        action.countUp(this.state.count + 1);
    }
    render() {
        return (
            <div>
                <button onClick={this.tick.bind(this)}>Count Up</button>
                <p>
                Count: {this.state.count}
                </p>
            </div>
        );
    }
}

Action -> (ActionCreator.js)

ここではcountUpメソッドが呼び出された際に、
Dispatcherにデータ全て横流ししています。

"use strict";
export default class ActionCreator {
    constructor(dispatcher) {
        this.dispatcher = dispatcher;
    }
    countUp(data) {
        this.dispatcher.emit("countUp", data);
    }
}

Dispatcher -> (EventEmitter.js)

下記の指示を行うためのプロセスを登録

  • カウンター値の更新
  • Viewの更新
"use strict";
export default class EventEmitter {
    constructor() {
        this._handlers = {};
    }

    on(type, handler) {
        if (typeof this._handlers[type] === 'undefined') {
            this._handlers[type] = [];
        }
        this._handlers[type].push(handler);
    }

    emit(type, data) {
        var handlers = this._handlers[type] || [];
        for (var i = 0; i < handlers.length; i++) {
            var handler = handlers[i];
            handler.call(this, data);
        }
    }
}

Store -> (Store.js)

??なぜEventEmitterを継承するんだろう…

constructor

  • 全体のデータセットを初期化(今回はカウントだけ)
  • Dispatcherをlistenするために窓口を作る(onメソッド)

onCountUpメソッド

Dispatcherから渡ってきたcountをStoreにて更新
画面を更新指示出しを行っている(emit)

"use strict";
import Emitter from "./EventEmitter"
export default class Store extends Emitter {
    constructor(dispatcher) {
        super();
        this.count = 0;

        dispatcher.on("countUp", this.onCountUp.bind(this));
    }
    getCount() {
        return this.count;
    }
    onCountUp(count) {
        this.count = count;
        this.emit("CHANGE");
    }
}

さいご

使ってみてFluxの良さわかってません。
自分で考えて作成しようと思います。
ただ、一方向のデータバインディングなのでわかりやすいし、自分のタスクに集中出来る所がいいですね。

一人で雑多AdventCalendarやっぞ

勝手にAdventCalendarやります。

やろうとしてることは下記

  • 技術記事(本当になんでもJS中心になるかも。)
  • アプリ制作途中経過報告
  • 愚痴

最近は私生活というか今後生きていくために
色々と忙しいけどこれくらい出来なくて何がエンジニアなんだってことでやりきってみたい。

初日からサボりそうで怖い・・・・