0

coffeeからES6(babel)に少しずつ書き換える

coffee-scriptで書いていたwebアプリをES6(babel)に書きなおした。

全部を一気に書き直してハイ動いたーとやるのは無理なので、coffeeとES6のファイルが混在しても動かせるようにして、少しずつ書き直した。


書き直したのはこれ
React+Fluxxor+socket.ioでfluxなチャットを作った
https://github.com/shokai/node-flux-boilerplate

インストール

% npm install babel babelify browserify watchify -save-dev
とやっていたのだが、数日前にbabelが5から6にアップデートされて、babel-coreやbabel-preset-*など色々分割されて、大分色々変わってしまった。周辺ツールも対応の過渡期だったのでbabel5系を使うようにバージョンを指定した。

  "devDependencies": {
"babel": "~5",
"babelify": "~6",
"browserify": "~11",
"watchify": "~3.5"
}


クライアント側


coffeeで書いたReactのプログラムをbrowserifyでjsに変換して1ファイルに固めていたので、単純にtransformを複数指定してやったらES6とcoffeeを混在しても大丈夫になった。

% browserify --debug --extension=.cjsx --extension=.coffee --extension=.es6 -t babelify -t coffee-reactify client/app.jsx -o public/js/bundle.js

coffeeもES6もまとめてES5になってbundle.jsができる
もちろんwatchifyでも同様にES6/coffee混在可能。

babel6だったらたぶんこれで混在できる。browserifyやbabelifyも最新に上げてから
% browserify --debug --extension=.cjsx --extension=.coffee --extension=.es6 -t [ babelify --presets [ react es2015 ] ] -t coffee-reactify client/app.jsx -o public/js/bundle.js


サーバー側

サーバー側はregisterを使う。registerはrequire関数をhookして実行前に翻訳してくれるしくみなので、例えばbabel/registerを使うとcoffeeからES6をrequireして実行できる。

Require Hook · Babel
register.coffee

最初に起動するファイルがserver.coffeeの場合

こうやってアプリを起動している場合
% coffee server.coffee # 起動

babel/registerで動的にES6を実行できるようにする。server.coffeeのなるべく上の方で

require "babel/register"

を書いておくと、これで以後coffee内からES6をrequireするとbabelが逐次変換してくれるので、混ぜて書ける。
require "models/user" # user.coffeeが読み込まれる
require "controller/main.es6" # main.es6が読み込まれる

babel 6.x系だと別のnpmに切り出されて、babel-core/registerに変わった。


最初に起動するファイルがserver.es6の場合


最初に呼び出すファイルをES6で書きなおしたら、
% babel-node server.es6 # 起動

coffee-script/registerで動的にcoffeeを実行する。server.es6のなるべく上の方で
require("coffee-script/register");

以後ES6なスクリプトからcoffeeをimport/requireすると逐次変換して実行される。

同じファイル名の.coffeeと.es6があったらどうするか

拡張子まで書けば指定できる。
require("foo.es6");

ES6に統一し終わったら.coffeeファイルを消して、requireの拡張子も消せばok
require("foo");


npmの場合

coffeeで書いてES5にトランスパイルしてnpmjs.orgにリリースしているプロジェクトを部分的にES6で書き直す場合は、試してないけどたぶんビルドプロセスを
coffeeの変換の後にbabelの変換、という順に実行してbabel側のファイルで上書きしてやるようにすればいいのではないかと思う。

0

ブラウザ/NodeでKORG nanoKONTROL1/2を使えるライブラリをES6で作った

作った。

https://www.npmjs.com/package/korg-nano-kontrol

% npm i korg-nano-kontrol -save

ブラウザならWeb MIDI APIで、Nodeならmidi npmでMIDIコントローラと通信するようになっているのでrequireすればあとは適当に動く。
あと、最初coffeeで書いて全部完成したんだけどbabel(ES6)で書き直してみた。というのもES6は前々から使ってみたかったんだけど、1から機能を1つずつ勉強するのは苦手なので、既に慣れてるcoffeeの機能をフルに使ってある程度の大きさの物を実装してからES6で書きなおす事で色々な機能を一気に使わざるを得ない状況を作って勉強してみた。

KORG nanoKONTROLとは

EdisonとMIDIコントローラでHueを調光する
とか
Node.jsとMIDIコントローラでHueを調光する
で使っている便利なMIDIコントローラー。ツマミとスライダーがたくさん付いている。

もともとkorg-nanoというライブラリがある

んだけど、nanoKONTROL2に対応していなかったのと、修正しようにも2つのデバイスに対応するなら1から作ったほうが早そうな設計だったのでついでにWeb MIDI APIにも対応させて作ってみた。

使いやすかったのでAPIはほぼそのままにしてある。

使う


connect()するとPromiseが返ってくる
var nanoKONTROL = require('korg-nano-kontrol');

nanoKONTROL.connect()
.then(function(device){
console.log('connected!' + device.name);
// do something
})
.catch(function(err){
console.error(err);
});

で、

device.on('slider:0', function(value){ // スライダー0番を取得
console.log("slider:0 >>> "+value);
});
とか
device.on('knob:*', function(value){ // 全ノブ取得
console.log(this.event+' => '+value);
});
とかすると取れる。



Web MIDI API

ブラウザでもBrowserifyで固めれば同様に使える



EventEmitter2

EventEmitter2にはワイルドカードでイベントを受け取れる機能がある。上でdevice.on(“knob:*”, func)とかやってるのがそれ。

ES6ではclass nanoKONTROL2 extends EventEmitter2して、コンストラクタの中でsuper({wildcard: true, delimiter: “:”})したら有効になった。


coffeeからbabel(ES6)に書き直した

簡単に感想を列挙すると

coffee-scriptよりは機能が少ない。
coffeeのfor k,v of objでkey/valueを回せるのと、do (arg) ->でクロージャ即時実行と、添字付きfor文と後置if文が使いたい。
でもfor ofはES6組み込みクラスのMapをイテレータでfor [k,v] of Mapすればいいし、doはletがあれば必要ない。

unlessがほしい。ifに!つけるのつらい。
関数宣言する時にexport付ければexportできるのは便利。
テンプレート文字列もよい。
[3…8]みたいなのはlodashの_.range(3,8)で代用できる。
関数のデフォルトパラメータ指定便利。
classは違和感なく書ける。getter/setterやstaticの定義も便利。
for(let i of array)を使うとnode 0.12やChromeでは動くけど0.10やSafariでは動かないJSができる。Symbol is not definedエラーが出る。

coffeeで書くのに比べてコード量は1.3倍ぐらいになる。
でもまあ、node 0.12以上で動かすならどっちで書いてもいいかなという感じがした。
古い環境をターゲットにするならcoffeeの方が安心感がある。

ESLint

lintツールにESLintを使ってみた。coffee-lintより色々しっかり見てくれてる気がする。

.eslintrcを置くと全ルールがカスタムできてよい。

parserにbabel-eslintを指定するとES6がlintできる。


gruntやめてnpm runにした

参考:Grunt/Gulpで憔悴したおっさんの話 – MOL

grunt-babelが複数ファイルの変換設定がかっこよく書けないのと、gulpがやはり理解不能なのでコンパイルはbabel –watchでいいやと思った。

parallelshellで複数コマンド同時実行できるので、esw(eslint-watch)も一緒に実行してる。

あと、npm2.0からnpm run コマンド名 — 追加の引数という感じに–を挟むと引数を追加して実行できるので、babelのビルド設定をそのままに–watchを追加して実行できてよい。

watchという続けて書いたコマンドをファイル更新監視して実行してくれるnpmもあるんだけど、なんか反応が遅いのでeslint-watchとbabel –watchで良いやとなった。これだとEdison上でもサクサク動いて良い。
package.json
  "scripts": {
"test": "eslint src/*.es6 src/*/*.es6",
"build": "babel src/ --out-dir lib/ --source-maps inline",
"watch": "parallelshell 'npm run build -- --watch' 'esw src/ --watch'",
"buildSample": "browserify --debug samples/webmidi/src/main.js -o samples/webmidi/dist/bundle.js"
},