読者です 読者をやめる 読者になる 読者になる

Node学園祭2016を開催します。 #nodefest

あと一ヶ月、早いものです。 というわけで、Node学園祭の 2016 を開催します。

nodefest.jp

今回のエントリはNode学園祭内でどういうことをやるのか事前にシェアしておくことで参加者並びに発表者の皆様にスムーズな参加を促すための紹介エントリです。

今回のコンテンツの紹介をします。

今回は2 days!!

今回は2日開催します。土曜と日曜日、土曜日がNodeSchoolを中心としてワークショップ形式のコンテンツです。日曜日がNode学園祭のキーノート形式のコンテンツです。

これまで1dayだけで濃縮させて実施してたんですが、さすがに無理があると思ったので2daysに分けることにしました。

1st day

f:id:yosuke_furukawa:20161010215957p:plain

まず、初日は dots で開催します。NodeSchoolや NodeDiscussionや CodeAndLearn 等、ワークショップコンテンツが豊富に配置されています。

NodeSchool

NodeSchool は基本的に Node.js 触ったこと無いという方に向けてのチュートリアルです。下記のコンテンツを提供する予定です。

  • javascripting (JavaScriptのワークショップ、変数宣言から関数定義とかifとかforの書き方まで含まれてる初心者向けワークショップ)
  • learnyounode (Node.jsのワークショップ、NodeのAPIであるfsやhttpを使って実際にNode.jsでCLIを作ったりサーバを作る初心者向けワークショップ)
  • how-to-npm (npmのワークショップ、npmのコマンドの使い方と基本的な一連の流れを学べるワークショップ)
  • learnyoureact (tako_blackさんが作った React を学べるworkshop)
  • tower-of-babel (僕が作った ES2015/ES6を学べるworkshop)
  • electronica (僕が作った Electron workshop)

ふつーの javascript ワークショップから npm, babel, react, electron といったコンテンツがチュートリアルとして実施されます。もしかしたら講師の方から新しくワークショップが追加される可能性もあります。

NodeDiscussion

NodeDiscussion は前回と同様、今回来てくれる James Snell, Bradley Meck, Mathius Buus, Yoshua Wuyts, Cheng Zhao, (maybe Douglas Crockford) に対して日本の皆さんからの意見を言う場を提供しています。前回と回答してくれる人が違う分、得られる回答も違うと思います。

James は Node Core Memberであり、いま Node の HTTP2 in core を進めている人でもあります。 Bradley は ES Modules との interop を取ろうとするためのプロポーザルを書いている人物です。 Mathius は Stream Hacker の一人です、さらにたくさんのnpmリポジトリを書いています。 Yoshua は choo というフロントエンドフレームワークを書いている人の一人だし、 Cheng Zhao 氏は、 Electron の作者です(あともしかしたら Douglas Crockford 氏も Discussion に参加してくれるかもしれません(スケジュール次第))。

豪華メンバーで今の Node.js に求めるものが何なのかを検討していく会にできればと思っています。

Paypal/BrainTree Workshop

今回はクレジットカード決済の PayPal から2つワークショップが追加されています。Paypal の使い方から BrainTree っていうサーバにクレジットカード情報を送らずともクライアントだけで決済完結できるためのライブラリの使い方までみっちりと紹介してくれます。

実際お金系の取り扱いはどうしても難しいところでもあるし、うっかりすると致命的な問題を引き起こしてサービス停止する可能性もあるので、これを機に是非学んでみることをおすすめします。

CodeAndLearn

今回のチャレンジングコンテンツの1つです。 CodeAndLearn は実際に node.js のコアリポジトリにコントリビュートしてみるというワークショップになっています。

Node.js のコアリポジトリへのコントリビュートの仕方は以前に記事で紹介しました。

yosuke-furukawa.hatenablog.com

しかしながら、実際にコントリビュートをしてみようと思うとそこのポイントを探すところからが難しく、"はじめの一歩"を踏み出す勇気も必要だと思います。今回の CodeAndLearn はこのはじめの一歩をみんなで学べるようにするためのワークショップです。こちらで「この辺りコントリビュートしやすいよ」的なポイントはまとめておきます。是非この機会にコアにコントリビュートしてみましょう。

LTs on 1st day

f:id:yosuke_furukawa:20161012022027p:plain

LT 大会も用意しています。初日はどちらかと言うとワークショップを中心としているので、LTもコアなネタは避けて割りと初級から中級者向けのトークを揃えました。

是非参加してください。

2nd day

f:id:yosuke_furukawa:20161012022411p:plain

2日目は例年通り CyberAgent で開催します。初日と2日目で場所が違うので気をつけてください。初日はdots、2日目はCyberAgent のある mark city で開催します。

nodefest.jp

今回、トーク応募がなんと60通近く来ており、その中からゲスト分を省いた12個のトークを選ばないといけないという状況でした。どのトークも面白そうだったのですが、スタッフ数名からのvoteとトークテーマの偏りを是正しつつ、なるべく新しく話してくれる人にフォーカスを当てる等、色んな気を使いながら選びました。選ばれなかった方は申し訳ありません。

nodefest.jp

特に海外からの応募が多く、全体的に英語セッションが多いので国際カンファレンスのようになっています。もうNode学園祭は日本のローカルミートアップではなくなり、「国際カンファレンス化してきている」というのをひしひしと感じます。

keynotes

さて、どの発表も濃いのですが、今回は Douglas Crockford 氏の基調講演があります。 Douglas Crockford 氏といえば、 The JavaScript Good Parts という本を書いた著者であり、 JSON という今ではほぼデファクトスタンダードになっているフォーマットを広めた人であり、 jslint という Linter の基礎を作った人でもあります。ECMAScript version 4 の仕様に終止符を打った人物でもあります。伝説のような開発者です。

どういう話をするのか、僕にもまだ明かされていません。僕も楽しみです。

他のトークは全て2本のトラックが並列で発表されています。朝から夜までぶっ通しでトークがあって、非常に楽しみです。 どのトークも胸を張ってオススメできます。今回はテーマのバランスを取るつもりでフロント向けのトーク(Vue.js/React/choo/PostCSS)もありますし、Nodeコアなトーク(WebStandard on Node/ES Modules)もあります、Electronなトーク(The Evolution of Electron)もあれば、ハードウェアハック(ファミコンハック&ラジオハック)もあります。サーバーサイド向けには GraphQL や now といったトークもあります。JavaScript のコアなトークもあります。分野の広い Node.js らしく、色んなテーマがごった煮で聞ける良い機会だと思います。

午前中に6本のトーク、午後は基調講演含めて13本のトークがあります。

かなりギュウギュウに詰めてしまったので見る方は大変かもしれませんが、この機会じゃないと見れないトークも多いので是非是非チェックして帰ってください。

LTs on 2nd day

f:id:yosuke_furukawa:20161012034330p:plain

2日目の LT も用意しております。2日目は初日とは違ってかなりコアな内容のものも増やしました。

懇親会

懇親会ではいつも通りコミュニケーションを中心とした懇親会をします。 いつもの通り、飛び込みLT大歓迎ですし、これを機会に海外ゲストと熱いトークをするのもおすすめです!

是非参加してください!!!

Node Interactive Europe 2016 に参加しました。

Node Interactive Europe とは

f:id:yosuke_furukawa:20160925115229p:plain

Node.js が Linux Foundation の傘下に入ったのですが、その Linux Foundation の支援を受けて開催される非常に大きなカンファレンスの1つです。アムステルダムで行われました。 とにかく濃い4日間で、今回は Node.js の発表あり、アンカンファレンスあり、Collaborators Meetupありで面白かったです。

First Date (Node Interactive)

初日、カンファレンスにはbreakfast/lunch がついていて、クロワッサンとスムージーがおいしい。

f:id:yosuke_furukawa:20160925093527p:plain

f:id:yosuke_furukawa:20160925115731p:plain

Node Foundation Opening Talk by Mikeal Rogers

f:id:yosuke_furukawa:20160925115841p:plain

Node.js のこれまでとこれからを表したまとめ的な話。 Node.js はサーバーだけじゃなくて、フロントエンドにも活用されるようになった( babel, browserify, webpack, gulp etc)

f:id:yosuke_furukawa:20160925204806p:plain

クライアントアプリケーションを作るためのフレームワークである、 Electron も流行している。

f:id:yosuke_furukawa:20160925204749p:plain

他にも IoT でも活用されてる ( Johnny Five, NodeBots, NodeCopter, とかのライブラリもそうだし、 tessel, arduino, raspberry PI, edison etc にも対応されてる )

f:id:yosuke_furukawa:20160925204719p:plain

クラウドサービスだと AWS Lambda , IBM BlueMix , GCP , Microsoft Azure などが API や Microservice 対応として Node.js を採用。

f:id:yosuke_furukawa:20160925205126p:plain

これまでの Node.js の話が包括的にされていて、かつ今回の Node Interactive Europe で話す各keynoteの先出しになっていて、聴講者の興味を刺激する良いトークだった。

発表者目線だとこんな感じ。 f:id:yosuke_furukawa:20160925204338p:plain

Node.js Core State of the Union by James Snell

f:id:yosuke_furukawa:20160926034611p:plain

Node.js Core の James、今年の NodeFest ゲストの一人。

Node.js はどんどんコミットされてかなり変更が加わっている、1年前のv4のときと比べると2700以上のコミットがある。 それの 49% はドキュメントやテストやbenchmarkで、より安定に向けて進んでいる。

f:id:yosuke_furukawa:20160927133135p:plain

benckmark の結果、v4とv6でパフォーマンスは上がっていて、しかも性能は安定している。大幅な落ち込みなどが無いことが分かる。

f:id:yosuke_furukawa:20160927133928p:plain

今後は Web Standard の方向を目指している。 HTTP/2 の話が eps (enhanced proposal specsといって、coreへの提案仕様) に上がるようになった。

f:id:yosuke_furukawa:20160927154614p:plain

async-await という新しい非同期処理手法も v8 で実装されている(ただし、Nodeで使える時期は未定)

f:id:yosuke_furukawa:20160927155142p:plain

ES Modules の話もある。ただし、この問題は根深くていまだ議論中。

f:id:yosuke_furukawa:20160927155414p:plain

Async-Hook という EventLoop のライフサイクルにおいて、イベントをフックできる仕組みを検討中。これはローレイヤのAPIになる予定。

f:id:yosuke_furukawa:20160927161816p:plain

V8 の上にVMを検討、V8以外のエンジン(ChakraCore, SpiderMonkey, JSC etc) も載せられるようにするために一旦中間レイヤを置く予定。

f:id:yosuke_furukawa:20160927170633p:plain

Stream API を native layer でも使えるように新しいnative APIを検討。

f:id:yosuke_furukawa:20160927170816p:plain

新しく ABI の機能を追加、 native addon を作りやすくするように。

f:id:yosuke_furukawa:20160927170546p:plain

ElectronとかIoTのようなembed向けに軽量化の提案。

f:id:yosuke_furukawa:20160927170835p:plain

国際化対応をより改善していく予定、実際にはデータセットを簡単に検索できるようにする

f:id:yosuke_furukawa:20160927171111p:plain

Debug 用に core dump analytics ができるようにしていく。 Node Report の仕組みを検討中

f:id:yosuke_furukawa:20160927171406p:plain

Node.js が今取り組んでいること、今後が分かるトーク。面白かった。

f:id:yosuke_furukawa:20160927171627p:plain

Node Together by Ashley Williams

slide: https://ashleygwilliams.github.io/nodetogether-keynote/#1

f:id:yosuke_furukawa:20160927171823p:plain

Node Together という inclusivity を向上させるためのカンファレンスについてのトーク。 これまであんまり node に触れてこなかった人たちや、やってみたかったけど CLI とかわかんないし Node の初め方もわからないような人たちに対して、みんなで一緒にやっていこうという道を示すためのカンファレンスが、 NodeTogether 。

NodeTogether

現在、 Node のコアメンバーは基本的に男性で構成されているし、女性が全くいないし、人種もアジア人が少なかったりと偏った状態、本来は色んな人の意見を聞くのが inclusivity の本質なので、これをなるべく是正していきたいとする活動(アファーマティブアクションという)。

f:id:yosuke_furukawa:20160927175442p:plain

「Node には inclusivity の問題がある」これを一旦全員で問題としてシェアするところから初めたいという考えさせられるテーマ。 日本でも Node Together JP を開きたいという話を最後に Ashley と話したところ、「ぜひやってほしい、支援が欲しかったら言って!」とのことなので実施していこうと思う。

EventLoop, yay by Bert Belder

slide: EventLoop, yay

f:id:yosuke_furukawa:20160928005648p:plain

EventLoop の話とその詳細について。EventLoop の図は間違いが多く、正確に EventLoop が理解されていることはじつは少ない。 下の図では ThreadPool の中に Network が入っている。 Network は実際には Thread で扱っていない(epoll/kqueue/ etcなので、正確にはスレッドじゃない)

f:id:yosuke_furukawa:20160928010314p:plain

こっちの図は Non-Blocking Worker という実際には存在しない worker がいたり、 その worker が client に値を返すような事が書いてある

f:id:yosuke_furukawa:20160928010507p:plain

こっちの図は Event Stack と呼ばれるスタックが存在している。こんな風にイベントを stack に溜めたりしない。

f:id:yosuke_furukawa:20160928011140p:plain

EventLoop は実際にはそのプラットフォームごとに微妙にやることが違うので、画一的な図にしにくく、抽象的な絵になる。 Bert が書くとしたらこういう感じ。

f:id:yosuke_furukawa:20160928011313p:plain

Node.js の中ではネットワーク以外にも色んな非同期処理がある、それぞれを統一的に非同期処理として隠蔽するために下の方ではスレッドだったり、kernel操作だったり、シグナルハンドリングで処理をしている。

f:id:yosuke_furukawa:20160928011729p:plain

Callback/nextTick/Promise も1つのイベントループだけではない、タスク処理をしている。

f:id:yosuke_furukawa:20160928011947p:plain

ものすごく面白かった。ちょうどタイムリーにもこの前Software Design 2016/10号に似たような話を書いていたのでためになった。

The Road Forward by Tracy Hinds

f:id:yosuke_furukawa:20160928013338p:plain

Inclusivity の話を再び。ちょっと違った目線から。Node.jsは先程 Inclusivity の問題がある、としていたが、それを実際に解消するにはどうしたらいいか、というトーク。どうやって Welcome な空気を作って沢山の人に contribute してもらうか。

  • アクセスするバリアをなくす
  • バイアスを減らす
  • みんなが安心して contribute できるようにする

というテーマ。二回も Inclusivity トピックが上がるというのはやっぱり課題はあるのだろうし、そこを声高に発言する必要に迫られているのだろう。

Isomorphic JavaScript with React by Azat Mardan

slide: github.com

Reactで Isomorphic JS を作ってみようという話。実際に実務で同じようなことをやってるので、わかりやすかった。

f:id:yosuke_furukawa:20160928090511p:plain

f:id:yosuke_furukawa:20160928091807p:plain

サーバーサイドレンダリングの問題はまだ良いソリューションはなさそうなので、地道にイベントループを止めない仕組みを検討するか自分でキャッシュ機構を作ったりする必要がありそう。

The CITGM Diaries by Myles Borins

slide: The CITGM Diaries

f:id:yosuke_furukawa:20160929022332p:plain

Canary In The Gold Mine と呼ばれる、Node.js がCIでやってる smoke test の仕組み、長いのでcitgmと呼ばれる。仕組みとしては CI の中で citgm を動かして、よく使われてそうなライブラリを最新のNode.jsでリリース前にテストできるようにする。

実績も上げていて、実は非常に使い勝手が良いライブラリ。自分でも動かすことができるので、自分達のライブラリでcitgmを動かしてみたいと思ったら下記のようにすれば良い

$ npm install citgm -g
$ citgm <module-name>

Text Mining with Node.js by Philipp Burckhardt

slide: https://eventmobi.com/api/events/13516/documents/download/84cffc82-bf57-4803-b7fe-6fed36d247f1.pdf/as/TextMiningTalk.pdf

Node.jsでテキストマイニング処理をしようとする人の話、Text Mining は機械学習ブームで色んな言語で実証が進んでるけど、やっぱりそこまで Node.js では進んでいない中で、色々ライブラリを構築していくっていう気概を感じる良い話だった。

この辺のライブラリの話だった。

github.com

github.com

Evolving Web Standards in Node.js by James Snell

HTTP2 in Core の話。 Node.js にも HTTP2 を持ってこようという話で、なるべく既存の http/https とのAPI差分を zero に使えるようにする予定とのこと。

HTTP2の HoL Blocking 回避の話や現状で nghttp2 を使って実現する話などの設計が共有されていた。

ただ実際に http2 と http1 で同じAPIを提供しようとすることはできても、その capability が異なるので、それは別途 low level な API も新たに追加する予定、一旦 nghttp2 を普通に使えるようにしたものを下記リポジトリで公開するのでできたらそこにフィードバックとPRがほしいとのこと。

github.com

The Cost Of Logging by Matteo Collina

pino っていうロギングライブラリ、性能が他の bunyan や winston とくらべても速いという事で、性能を売りにしている。

github.com

pino よりも性能を計測するためにボトルネックを調査する方法として 0x と autocannon というライブラリが使われててそっちが面白かった。

0x は flamegraph を簡単に作るライブラリ

www.npmjs.com

autocannon は ab テストみたいにリクエストを送るツール、http pipeline に対応している

www.npmjs.com

Building the Node.js Global Distribution Network by Guillermo Rauch

最近 Guille が作った会社の zeit でやっている now というツールに関してのプレゼン

now はものすごく簡単にクラウド上に自分のサーバーを建てられるサービスで、雑に言えば npm install now -g して now deployment <your_server_code_path> したら後は待つだけでデプロイできる。

ただし、持っているのはコンピューティングリソースだけで、データリソースとしては別な所を借りてくる必要がある。

初日のまとめ

  • Nodeのこれまでとこれからの話がメインに語られてた
  • 他のはライブラリを使ったトークで、ノウハウが多くて面白かった。大体日本と語っている内容は似てても、向こうはちゃんとライブラリのauthorが語るのでちょっと違った雰囲気になる

飲み会で、最近どんなhackyな話題あるの?って聞いてみたら 「Rust いいよ Rust」って言われて割りとみんな新しいものに手を出してる感じが良かった。

Second Date

さて、2日目。この日で Node Interactive Europe としてのカンファレンスは最終日、3日目と4日目はコラボレーターのための日になる。

Bitcoin, Blockchain and Node by Portia Burton

slide:

Bitcoin と Blockchain っていう今丁度盛り上がっている分野のトーク。

特に Blockchain にフォーカスしていて、とりあえずやってみたかったら Etherum っていうプログラマブルに blockchain を使えるプロジェクトがあるからそこから参画していくと良いという紹介だった。

github.com

勉強不足でわからないことが多いので、この分野はもう少し手を動かして学んでいく必要があるなと思った。

Elegantly Produce and Consume Compiled Packages by Benjamin Lupton

slide:

Compiled な Modules を作る時のエレガントな方法というタイトル、実際に今は babel だの TypeScript だのでコンパイルされるライブラリが多い。さらに言えばモジュールを作る時に READMEだけじゃなくて色々本来は必要なファイルもある(CONTRIBUTING.mdとか)

editions というライブラリでその手の問題を解決しようという話だった。

www.npmjs.com

Ambitious Desktop Apps with JavaScript and Electron by Felix Rieseberg

slide:

Slack のエンジニアからの Electron アプリの話。

f:id:yosuke_furukawa:20160930024350p:plain

Programming for the NES with JS

slide: http://fritzvd.com/talks/node-ie-nes/#1

ファミコンJavaScriptでハックする話。この辺のエントリが元になっている話。

Getting started with NES programming · fritzvd

独特の発表スタイルwそして、マッドサイエンティストな感じのハックですごく面白かった。

Alt-Ctrl: Scream into this Arduino by Rachel White

f:id:yosuke_furukawa:20160930025217p:plain

Arduino に向かって叫べ!っていうタイトル、熱い。 自動でネコに餌をやる仕組みを作ったりと根っからのハードウェアハッカー。 今回は Node.js で Arduino に向かって叫ぶとLチカするようなデモをしたりといくつかデモでArduinoだったりNodeBotsの面白さをintroductionしてくれた。

f:id:yosuke_furukawa:20160930030118p:plain

npm v4/v5 by Kat Marchan

npm v4 と v5 の話 by Kat Marchan

npm v3 はもうそろそろリリースされて1歳になる。LTSとして今後はメンテナンスフェーズに移る。次は npm v4。

f:id:yosuke_furukawa:20160930030216p:plain

npm v4 は v3 のときほど大きな変更はしない予定。10月リリース予定。

f:id:yosuke_furukawa:20160930030236p:plain

node path の prepend をデフォルトではオフに。 もともと npm v3 は現在の Node の path が勝手に prepend される仕様。オプションで追加できるように修正する予定。

f:id:yosuke_furukawa:20160930031400p:plain

npm search の復活、 incremental search がcache機能でできるようにする。

f:id:yosuke_furukawa:20160930031635p:plain

prepublishは install 時も行われる分かりにくい仕様なので、 deprecated その代わりに prepare 用のhookを追加、これが prepublish 相当の動きをする。本当に publish の前で行う prepublishOnly というhookも設置予定。prepublishOnlyは deprecated の prepublish が浸透したら、ゆくゆく名前を prepublish に直す。

f:id:yosuke_furukawa:20160930031651p:plain

npm v5 は shrinkwrap の改善にフォーカスする。 2017年 first quarter 中を目処に実施する予定。

State of the Union : Express by Doug Wilson

Express の現在のメインメンテナである Doug Wilsonからの今後の Express の話。

Express とは言わずと知れたウェブアプリケーションフレームワーク、 router の仕組みと thin な middleware から成る。

f:id:yosuke_furukawa:20160930032332p:plain

Express は Node Foundation に incubating project として追加された。長期メンテ保証されるようにコラボレーションの仕組みを作っている。

f:id:yosuke_furukawa:20160930032425p:plain

Express は内部的に3つの organizationを持つ。

f:id:yosuke_furukawa:20160930032554p:plain

それぞれの役割はこんな感じ。

f:id:yosuke_furukawa:20160930032641p:plain

Express v5.0 に向けては下記のようにしていく。

  • Promise をサポートする
  • template engine 改善
  • cookie/querystring 処理の改善
  • route syntax を新しくする
  • よりコアを細分化していく。

f:id:yosuke_furukawa:20160930032721p:plain

2日目まとめ

  • npm が v4 / v5 のロードマップを見せた
  • Express v5 で Promise が!

これで一旦カンファレンスは終了、 Node v7 あり、 npm v4, v5 あり、他のたくさんのモジュールの解説ありで非常に有意義なイベントだった。

Third Date

ここから先はそこまで語るところはないのでかいつまんで。 三日目は、 contribution のやり方に主眼をおいてみんなでアンカンファレンス形式でトークしつつも、 code and learn っていう実際にコントリビュートをその場でレクチャーする話が面白かった。

libuv v2 talks by saghul

libuv v2 どうするかという話、 saghul, bert belder, bnoordhuis, が一同に介して libuv の話するとか胸熱な感じだった。 f:id:yosuke_furukawa:20160930033732p:plain

libuv v2は既に master branch にマージされていて、新APIやplatform 依存コードの cleanup などが進んでいる。 f:id:yosuke_furukawa:20160930034220p:plain

いまだに libuv のだめな所、主にdocumentationが弱点。 f:id:yosuke_furukawa:20160930034353p:plain

uvbookに書いてある内容を統合しつつ、サンプルを増やす(http clientとか) f:id:yosuke_furukawa:20160930034511p:plain

Multi-thread 改善も進める、スレッドセーフなAPIも追加する f:id:yosuke_furukawa:20160930034637p:plain

TLS サポートもしたいと思っている。 f:id:yosuke_furukawa:20160930034758p:plain

Device 対応 f:id:yosuke_furukawa:20160930034857p:plain

左から Fedor, Ben Noordhuis, Bert Belder, Saghul という libuv allstars f:id:yosuke_furukawa:20160930035016p:plain

Forth Date

最終日は、 Collaborators Meetup をして終了。長い長いカンファレンスだったが、途中にちゃんと面白い手を動かすようなカリキュラムもあって非常に刺激になった。

まさにこんな感じで、みんなで VMの話、 http2の話、inclusivityの話、release 管理の話をディスカッションした。やっぱりというか inclusivity の話が一番盛り上がって、全員で1時間以上トークしてしまった。

inclusivity は答えが無いので、トークしても発散気味になるが、今時点ではこれらの問題点がちゃんと共有されることがいちばん大事なのだろう。

まとめ

アムステルダムで4日間のカンファレンスに出席して、色々と話を聞いてきた。ものすごく面白い話が多くて、特にNode.jsの今後の話ができてよかった。 Node Interactive から Node学園祭に持ってこれるものも多いので、良い所は参考にして新しいコンテンツにしていこうと思う。

特に code-and-learn という Node Core にコントリビュートをしてみようというハンズオンが面白かったので、 Node 学園祭でも実施する予定だ。既に宣言はしてある。

github.com

今回のカンファレンスで得たものをなるべく NodeFest に還元していこうとおもう。

socket.io が提供してくれているものは何か

現在開発中のシステムにリアルタイムな処理があり、そこで socket.io を使おうかなと思ってて、そういう折にタイムリーにもこの辺りの記事がタイムラインで出てきたのでメモ代わりに自分の意見を残しておく。

blog.jxck.io

qiita.com

socket.io が提供してくれているもの

「ブラウザとサーバ間のプロトコル」という観点で見ると socket.ioWebSocket を基本として繋がらなかった時に XHR Long Pollingpolling といった形式の代替手段を提供してくれるもの、という位置づけ。

一方で「ライブラリ」という観点で見ると socket.io はリアルタイムアプリケーションを作る際に必要になる処理をまとめて実装し、クライアントとサーバ間での EventEmitter として抽象化してくれているもの、という風になる。

もう少し噛み砕いて言うと、 socket.io は WebSocket / Long Polling / Polling をラップした上で、さらに便利なAPIや機能を提供してくれるクライアント・サーバのライブラリ、と言ったら良いだろうか。

socket.io がトランスポートのネゴシエーション以外にどんな面倒事を引き受けてくれるかというと、大体以下の様な感じ。

  • 接続している全クライアントへのブロードキャスト処理
  • クライアント・サーバ間で ping-pong する事によるheartbeat確認
  • 接続が切れた時のクライアントの再接続処理
  • ルーム/ネームスペースによるコネクションの管理
  • 認可処理
  • 到達確認

この手の「大概リアルタイムアプリ作るとき必要になるでしょ」的な処理を socket.io が勝手に用意してくれている。 Simple と Easy の違いで言うと、 Easy な API を提供してくれるものだ。

あと細かく言うと socket.ioWebSocket から Long Polling / Polling の代替手段を提供する時に一回一回繋げるかどうか試しながら fallback するのではなく、『一旦全部繋いでみて、繋がったらその中から一番いいやつを採用する』という方式をとっている。これは初期接続の速度を速めるために採用した仕組みだったりする。

逆に言うと、 WebSocket でリアルタイムアプリ作るなら上述したような処理をクライアント・サーバで書く必要がある。

なので、 socket.io をやめて WebSocket だけで作るのもいいけど、 WebSocket は Simple な API であり、色々他にも必要な処理はある。もちろんそこまで難しいものでも無いので自分で書いても問題ないとは思うが、今開発中のプロダクトではそこまでする気にならないし、後述する『 WebSocket 繋がらない問題』もあるので socket.io を採用することにしている。

WebSocket 繋がらない問題

結論から言ってしまうと、WebSocketはWebSocket Secureにしたってつながらないこともある。なんで繋がらないのかはこの記事が詳しい。

qiita.com

ただし、それがどの程度の割合で繋がってて、どれ位のユーザーはつながらないのかというデータを僕含めて開発者はあまり持ってない。

前に WebSocket (not socket.io) 使ったゲームを作ってた時はモバイル向けでB2Cのアプリという事もあってか途中にproxyを挟まないからか、数万単位のユーザーがプレイしても接続不良等の問題は顕著になってなかった(掲示板などで意見収集をしてたが、繋がらないとかそういう声はなかった)。

ただ開発者が欲しいのはこういう"話"じゃなくて、アクセスログレベルで繋がってるかどうかの割合、繋がってるんだとしたらどれ位の期間維持できているのかという"指標になりうる値"だと思うので、今後開発する際はその辺りにも気を配りたい。

つながらないとした時の代替手段

単純に Server からの push としてみると WebSocket じゃなくても他に方法はある。 Server Sent Events がまさにそのケースにマッチする。

一方で、 WebSocket は push の機能だけじゃなく、双方向で通信が可能になるものなので、一方通行でサーバからしか送信しない push とは少し趣が異なる。WebSocketを使わずに双方向で通信するような処理をしたい時は Server Sent Events で実現する受信の機能と XHR での送信の機能を併用するような形を取る。

つまりはコネクションを2つ併用する形になる。ネットワークレイヤから見るとTCP接続2本貼ってて無駄はあるが、代替手段なのでしょうがない。

個人的な思い

このツイートで言いたかったことは終わりなんだけど、あんまりこの手のリアルタイムアプリ向けのライブラリが Node.js 以外でそこまで発展していないのかもしれない。

ただ、 Rails に最近入った ActionCable を見てみると、 上に書いたような socket.io が機能としてやってくれることは大体やっていたし、今はやってないけど多分すぐにトランスポート層ネゴシエーション機能も入ると思う。

また Elixir の phoenix にはトランスポート層ネゴシエーションまでやってるライブラリがあると聞いたので、この層を解決するようなフレームワークは増えている。それも含めて積極的に使って行ったほうが良いと思う。

2016年になってウェブの世界でもプロトコルは進化していて、より良いプロトコルがあるなら使った方がいいし、実際にユーザーがちゃんと使えているのかはモニタリングしておきたい。一方で互換性をちゃんと保つことも必要で、多少無駄があるとしても繋がる/使えるという状況は保つようにしていたい。

Node.js における Promise を使った例外処理

さて、 Node.js のエラーハンドリングは難しいと言われてますが、 2016年現在、つまりNodeの v4 とか v6 が主流になり、 Promise が基本的な処理として採用されている状況ではどうでしょうか。ちょっと考えてみます。 一応これの補足です。

qiita.com

TL;DR

未だに難しい。ただし、 Promise で改善されている。async-await や zone まで来たらかなり楽になる。 あと、 unhandledRejection が uncaughtException よりも酷いことにならないので、大分マシになっている。

Node.js のエラーハンドリングの難しさ

まず JavaScript には同期と非同期のエラーハンドリングのやり方があります。前者は所謂 try-catch による方法、後者は callback を使って第一引数で実現する方法や emit('error') - on('error') でイベントとして渡す方法等が存在します。

難しいとされるのはいくつかあって、同期と非同期が混じった時に画一的にハンドリングする方法が無いので、特に問題が起きます。

また JavaScriptJava とかと違って try-catch を書かなくてもコンパイルエラーにならない言語なので、 catch の書き漏れが起きやすい言語なわけです。catch を書き漏らすと Node.js のさらに上のレイヤで補足され、誰も catch しない場合に 最終的に processuncaughtException としてcatchされる事となり、そこではログに書いて落とす以外の選択肢が取れません(後述)。

非同期は非同期で on('error') って書くスタイルや callback のスタイルで混じります。前者は Stream というか EventEmitter を使った時の標準的な方法です、後者は最もベーシックなやり方で callback 関数の第一引数を必ず error に当てるというものです。

つまりは画一的なエラーハンドリング処理が存在しないというのが JavaScript における難しいところの1つです。

Promise

Promise を使うと上の状況を少しだけ回避できます。Promise が提供してくれるのはこの画一的なエラーハンドリングであり、 Promise の中で起きた例外は同期の throw であろうと reject であろうと全て catch されて、Promise の .catch の関数に来てくれます。よく callback-hell の解決策として登場する Promise ですが、Promiseが解決するのはエラーハンドリングのやり方でもあります。

.catch を書き忘れた場合には unhandledRejection という形で uncaughtException のように最終的に process の所でキャッチされます。ただし、これは uncaughtException ほど絶望的な状況じゃありません。

ただ別に Promise も例外処理を雑に扱える銀の弾丸じゃありません。 Stream / EventEmitter のように 連続でイベントが発生するようなものは Promise で表現できないので結局 .on('error') でのハンドリングは残ると思います。

uncaughtException と unhandledRejection について

uncaughtExceptionunhandledRejection もどちらも同じようにキャッチされなかった例外が process まで来てしまった時の例外ですが、認識しておいてもらいたいのは unhandledRejectionuncaughtException では処理の方法が全く異なる、という事です。

そもそもなんで uncaughtException ではprocessを落とさないといけないのか

uncaughtException で落ちないといけないのは、簡単にいえば、例外を v8(C++) の層でキャッチしているから、です。

github.com

github.com

Node.js はイベントループモデルで作られていますが、イベントループの状態や実行中のタスクがどうなるかとか無関係に uncaughtException が起きると v8 の C++ レイヤまで一気に突き抜けてキャッチされます。こうなってしまうともう継続不能です。イベントループがおかしくなって、結果エラーが出続ける可能性もあるし、EventEmitter で積んだはずのイベントがちゃんと処理されない可能性もあります。なので、継続するのは推奨されておらず、ログに書いて、プロセスを落としてから再起動させる以外の手段がありません。

ただ、もう少し深ぼると、 Node.js のJSレイヤで全体を try-catch で括れば C++ レイヤまで来ないようにすることも可能です。こうすると、少なくとも イベントループ がコントロールできない状況は防げる可能性はあります。これをしなかったのは、 v8 の最適化が try-catch のブロックが書かれた関数をJITで最適化しないという制約が存在するためです。性能を優先して、Node.js 内部ではこの方式は取られませんでした。

unhandledRejection ではなんでprocessは落ちなくていいのか

uncaughtExceptionC++ のレイヤでキャッチしているという話をしましたが、 unhandledRejection はJSレイヤで処理されています。

v8 の中のコードを見ると分かりますが、 Promise はほぼすべてのコードが JavaScript で記述されています。

github.com

uncaughtException の時と違って C++ のレイヤまで突き抜けることはありません。 Promise が中で try-catch しているので、unhandledRejection が起きた所でそれは JS の中のレイヤで起きている『try-catchで例外をcatchしたけど無視されている状況』です。少なくともイベントループの状態はおかしくなったりしません

また、 Promise としては unhandledRejection になった状態を別に禁止していません。その時点で unhandled な状態であったとしても別な時に catch される可能性があるためです。

結局のところ unhandledRejection が起きた所でそれをどうするかはユーザーのアプリケーションに依存する訳です。

process を継続したくない時のエラー

エラーの中には process が動き続けることでより深刻な状況になるエラーも存在します。『あり得ない状況』になっているのに無理に動き続けた結果、より深刻な問題になってしまう事もあります。

『この状況になったらアプリケーションが落ちる以外に打つ手がない』という時、これまでは例外を投げて uncaughtException として落とすことができましたが、 Promise で括ってしまうと、『プロセスを継続したくない時のエラー』だろうとなんでも catch されてしまいます。

結局のところ、 JavaScript には Java で言うところの非検査例外(RuntimeException)も無ければ、 golang で言うところの panic に相当するような処理もありません。

少し前に node symposiums という有識者だけで行われたイベントでこの辺りの『検査例外(checked exception)と非検査例外(unchecked exception)』を Promise でどう扱うかの話があったのですが、結局 JS の try-catchシンタックスを拡張するしかない上に、今のところこの手の話が TC39 で話されてるのも僕は知らないので、throw側 か catch側で工夫するしか無さそうです。

github.com

デフォルトの unhandledRejection の動き

今のところ、 Node.js は unhandledRejection が起きたとしてもデフォルトでは何も言いません。これは議論の最中です。

github.com

issue opener の意見としては、『unhandledRejectionが起きた時に何も言わないのはさすがにどうなのか、各種ブラウザの動きとも異なる』という話です。今のところ決定策は出てません。

ちなみに 各種ブラウザ動きが若干異なります。

  • Chrome は unhandledRejection が起きた時点にエラーとして出力して終わりです
  • FirefoxGC が発生した時にその段階で Promise が回収され、 rejection がハンドリングされなかったらエラーとして出力します
  • IE Edge は unhandledRejection で hook はできるけど、何も言わない??(未検証)

今後どうなりそうかで言うと

  • 単純に標準エラー出力に warn を吐くだけ (chrome 案)
  • GC で Promise に該当するオブジェクトが 回収された時にprocessを落とす (Firefox & uncaughtException の動きに合わせる案)
  • 何もしない (現状維持)

のあたりの案がありますが、個人的には現状維持かやっても chrome 案くらいかなと思っています。GCの時にデフォルトで落とすのは Promise.reject で最初からunhandledな例外オブジェクトを作れる以上、やり過ぎ感があるかなと。。

何も言わないのは一見不親切に見えるかもしれませんが、 unhandledRejection の動きをどうするべきかは、ユーザーのアプリケーションでどうするべきかを決めることであって、 Node.js が積極的に決めることではないので、デフォルトをどうするべきか難しいのです。こういう話は『機構と方針の分離』という話もあり、機構は用意するが、方針としては何も意見を出さないという姿勢を持つような処理系の哲学でもあります。

ちなみに Domain

Domain は中で uncaughtException を使って処理しているだけなので、もう使わないでください。 結局domainの領域でエラーがcatchできた所で uncaughtException が起きていると、再起動する以外に策はありません。

今後としては Zone に期待しましょう。

docs.google.com

まだ目下のところ stage 0 ですが、 domain 的に発生した exception を領域ごとにまとめて掴んで処理することができるようになるので、 unhandledRejection よりも細やかなエラーハンドリングが可能になります。Zone は中の実装がどうなるかまだ決まりきっていませんが、おそらく Promise のような機構を使って、 JSの内部で処理をすると考えられるので、 domain よりは使えるものになる可能性が高いです。

実際の所どうするべきか

ここから先は個人的な意見で、『自分がウェブアプリケーションサーバを Node.js で作るとしたらどういう風にエラーハンドリングをするべきか』を記述しておきます。

  • 基本的に Promise を使う
  • Web Application Framework のミドルウェアのレイヤできちんと例外を補足する
  • もしミドルウェアの外でエラーが起きても unhandledRejection を使ってエラーを補足する

基本的に Promise を使う

速度が問題になるのであれば、 これまでのスタイル(callback etc)をそのまま使ったほうがいいでしょう。ただ、所謂普通の web application のような後ろに DB があって、それをコールするような処理をするのであれば、 JIT 最適化で稼げる速度よりも IO の時間のほうが問題になるので、これまで callback で書いていたような所は Promise で置き換えても問題ないと思います。

Web Application Framework のミドルウェアのレイヤできちんと例外を補足する

koa v2 からは async-await ベースでミドルウェアが書けるようになり、 async 関数は Promise でラップされる、という事なので、 koa v2 を使えば微妙な try-catch の書き忘れで全体の process が落ちなきゃいけなくなるというようなことは避けることが可能です。

一方で express とか hapi だと、ミドルウェアは Promise ベースじゃないので try-catch の書き忘れにより、上記に上げたような uncaughtException が起きる可能性はまだまだ高いと言えるでしょう。

ただ express に関しては StrongLoop が出している記事で、babel + async-awaitを含めた今後のエラーハンドリングの方法が書いてあるので紹介します。

StrongLoop | Asynchronous Error Handling in Express with Promises, Generators and ES7

// promiseのエラーをキャッチして next に渡す関数を用意しておく
let wrap = fn => (...args) => fn(...args).catch(args[2])

// async 関数で middleware を書く、つまり middleware の中は Promise になる
app.get('/', wrap(async function (req, res) {
  let data = await queryDb()
  // handle data
  let csv = await makeCsv(data)
  // handle csv
}))

// もしもエラーが発生して、 try-catch を書き忘れたりしたとしても、 エラーハンドラにエラーが渡るので express のエラーになり、プロセスが落ちなくて済む
// エラーハンドラ
app.use(function(err, req, res, next) {
  res.status(500);
  res.send(err);
});

実際の所 try-catch でmiddleware内部を囲んでいるのとそこまで変わりません。本来であれば、try-catch を入れてエラーをその単位でちゃんとハンドリングするのが良いですが、万が一忘れたとしてもwrap関数でerrorがunhandledRejectionにならないようになってちゃんと 500 エラーになるように担保してくれます。(ほぼ koa に近づくような話ですね。)

ちなみに Stream と一緒に使うときは下記のようにします。

app.get('/', wrap(async (req, res, next) => {
  let company = await getCompanyById(req.query.id)
  let stream = getLogoStreamById(company.id)
  stream.on('error', next).pipe(res) // on error でフックしたエラーを next に渡す
}))

もしミドルウェアの外でエラーが起きても unhandledRejection を使ってエラーを補足する

さらに unhandledRejection を使って ミドルウェアの外で Promise のエラーが発生しても気がつけるようにしましょう。

callback スタイルの時は callback の第一引数に渡したエラーがハンドリングされるかどうかを ESLint なりの Linter でチェックできましたが、 Promise になると、エラーを catch しているかどうかを見るのは静的解析だけでは厳しいので、 unhandledRejection を入れてチェックするのをオススメします。特に開発期間中は変なtypoだったり、Nullpointer exception 的な問題で気づかないのは問題なので、 開発中は気付きやすいようにエラーログに入れたり、敢えて落とすようにしてチェックしやすくするのをオススメします。本番になったら unhandledRejection レイヤーでは基本的には何もしなくても問題のないケースがほとんどかと、強いてやるなら一応ログに書き出すくらいでしょうか。

if (process.env.NODE_ENV === 'development') {
  process.on('unhandledRejection', (err, p) => {
    // 開発中はログに出力する
    console.error('Error : ', err);
    console.error('Promise : ', p);
    // もしも気づくのを早めたかったら落とすとか
    // throw err;
  });
}

process.on('unhandledRejection', (err, p) => {
  // 本番では何もしない
  // もしも何かしたければ、せめてログに書く等
  // logger.error(err, p);
});

process.on('uncaughtException', (err) => {
  console.error(err);
  process.abort(); // uncaughtException の時は落ちる
});

まとめ

  • Promise を使うとエラーを画一的に処理できる
  • unhandledRejection と uncaughtException の違い
  • checked exception と unchecked exception
  • Node.js では Promise の unhandledRejection が起きても何も言わない
  • domain はもう使わない
  • 現時点で Web アプリを作る場合はどうするべきかという私見

OpenCV + Google Cloud Vision API + Intel Edison で笑った瞬間を撮るカメラを作る

やりたいこと

最近娘が生まれて二ヶ月経過し、そろそろ笑ったりするようになりました。今回のテーマは娘が笑った瞬間を逃さずにカメラで撮影する事です。ちなみにこういう子どもをネタにして行うハック、僕はこれを『親バカハック』と呼んでます。

f:id:yosuke_furukawa:20160608084338p:plain

TL; DR

  1. Intel Edison でカメラをセット、一定のタイミングで撮影しつつ
  2. OpenCV で粗く笑顔認識させてから
  3. Google Cloud Vision API で表情解析
  4. 笑顔だと判定された画像を Slack で飛ばして画像をいつでも見れるようにする。

f:id:yosuke_furukawa:20160608102239p:plain

かわいい笑顔が撮れたので最高でした。

ハードウェアセットアップ

Intel Edisonを手に入れたのでそれを使って作ります。Edison は Arduino 拡張ボードなら普通のUSB web camera 対応しているので、それをただぶっさして使います。

f:id:yosuke_furukawa:20160608084105p:plain

Intel Edison はSDカードほど小さくて、 x86Intel Atom というプロセッサーを積んでます。あんまり詳しくないのですが、筆者が大学の頃、太古の昔の教科書では x86CISC系は組み込み系に弱くて、 ARM の RISC系のが組み込みに有利という認識だったのですが、どうやら時代は変わって今ならどっちもどっちでx86なのに組み込み系に乗る時代になったようです。

ともかく、 Edison にしたのはただ『そこにあったから』です。Noderとしては Intel Edison を初期化した時に最初からnode.js v0.12 が入ってるので嬉しい(頼むからv4+にしてほしい)。本当は Intel Edison じゃなくても良くて、一番試してみたかったのは Tessel 2 なんですが、日本で手に入れるのは難しいという話だったので、一旦 Edison でトライ。

Edison がうまくつながっていれば USB web camera をただ USB port にさすだけで使えるのですが、初期の頃はさしただけで使えなくてあれこれ調べて SW1 スイッチを USB 側にしないと使えないようです(ハマりどころ)。

dev.classmethod.jp

ちなみにほぼこれを参考にすればハードウェアのセットアップは終わります。

github.com

笑顔認識

顔画像を認識させるのは OpenCV で簡単にできるんですが、さらに笑顔認識までしようとすると、多少の小細工が必要です。 OpenCVCascade Classifier という機能を持っています。これは名前の通り、 分類器(classifier)を連結(cascade)させて特定するという機能です。笑顔認識で言えば、

  1. 顔画像領域を特定(画像の中から眼や鼻や口といった特徴のある領域を抜き出)し

f:id:yosuke_furukawa:20160608105656p:plain

  1. その顔画像領域の中で笑顔かどうか(顔の下半分に半月/三日月形の領域があるか)を特定する

f:id:yosuke_furukawa:20160608105722p:plain

という二段構えの分類機能の組み合わせで成立しています。 今回の OpenCV でやっているのは非常に単純かつ強力な仕組みで、2001年くらいの論文で解説されている Viola Jones Object Detection と呼ばれるものです。2001年の頃の論文が今ではライブラリとして簡単に扱えるので良い時代になったなと思ったのですが、残念ながらこの方法はそこまで精度が良くないです。構造が単純で解析に時間がかからないのが特徴です。

笑顔検出は npm モジュールから使えるようにライブラリにしています。

github.com

この smile-face-detector を使ってリアルタイムでデモする動画をとってみました。 ちなみに web 屋っぽく websocket で配信する仕組みです。

smile

github.com

Google Cloud Vision API を使って表情解析する

OpenCV で笑ったと判断したとしても、やっていることは『顔の下半分に半月形の領域があるかどうか』、なので本当に笑っているかどうかはまだ難しいです。そこは表情解析に定評のある Google Cloud Vision API というクラウドの力を借ります。

Google Cloud Vision API は表情解析、風景解析、画像内のOCR、画像内のオブジェクト認識ととんでもなく強力な機能を持った GoogleAPI です。これを使っただけでも何かできそうな気がしてきます。

Google Cloud Vision API は表情解析して、その表情から読み取れる感情が happy なのかそれとも sad なのか、はたまた surprised なのかといった結果を返してくれます。

http://cdn.mos.techradar.com/art/internet/Google/Cloud_Vision_API-970-80.jpg

ただやはりリアルタイムに解析するにはネットワーク通信のコストがかかるのとどうしても時間がかかる、あと、無料枠では1日1000リクエストまでなので、やたらめったらに送る訳にはいかないという制限があります。なので OpenCV での一旦フィルタを使って OpenCV で笑ってると判断された画像だけを Google Cloud Vision API に送るという仕組みにしています。

笑顔が検出されたら Slack に転送する

Google Cloud Vision API が happy だと判定してくれたら後は楽で、その画像を Slack に送ります。

f:id:yosuke_furukawa:20160608084338p:plain

github.com

外出中とか仕事中でもかわいい画像が見れて便利です。

はーかわいい

ただし

何日間か試して思いましたが、以下の点でこの仕組のままでは厳しいです。

1. Intel Edison がそこまで高速ではない

Intel Edison は 500MHz で dual core と組み込み系の中では高速ですが、さすがに1,2秒間隔で OpenCV を回し続けると不安定になります。 そこはやはり Raspberry PI 3 とかだと 1.2GHz quad core になるとのことなのでハードウェア側をもう少しCPUリソースが使えるものにする必要があります。もしくはC++とかで直接OpenCVを使うといいのかもしれません。

2. 首の座っていない赤ちゃんは顔画像特定が難しい

これはもうどうしようもないんですけど、まだ赤ちゃんの首が座ってないので OpenCV では正面をちゃんと向いていないと顔画像として認識してくれないので難しいです。なので顔が写ってても取りこぼすこともしばしば。これを解決するには画像を少しずつ角度を変えて実行する必要があるんですが、そうするとどうしてもさらに時間がかかってしまいます。

3. 親が笑ってると思ってもGoogle Cloud Vision API は笑ってないと判定する

自分から見ると笑ってて可愛い笑顔だなーと思って Google Cloud Vision API にかけると全くの「無表情」として帰ってきます。 Google Cloud Vision API が判定してくれるのはもっと分かりやすい笑顔なので、そこまではっきりとした笑顔になるためにはもう少し赤ちゃんの成長が必要です。

とはいえ

一旦丸3日位やってみたら、こういう可愛い笑顔が撮れました。

f:id:yosuke_furukawa:20160608102239p:plain

今はもう少し赤ちゃんの状況に合わせてリアルタイムに笑顔を撮るんじゃなくて、90秒間隔くらいで Google Cloud Vision API にかけながらSlackで様子を見てます。

f:id:yosuke_furukawa:20160608143537p:plain

まとめ

OpenCV + Google Cloud Vision API + Intel Edison で笑った瞬間を撮って、 Slack に送るカメラを作ってみました。 もう少し時間があったらEdisonじゃないハードウェアとかで試してみようかなと思います。

また Node.js で全部できそうだったので、Nodeで実現したけど、リソース効率を考えるともう少しシステムプログラミングよりの言語(CとかC++とかRust(?))を使ったほうがいいのかもしれません。

この辺も時間があったら試してみます。

ES Modules と Node.js について

書こう書こうと思いながらこのタイミングまでのがしてしまいました。 今一番 Node.js の中で hot な discussion の一つと言えるでしょう、『ES Modules が Node.js の中でどうなるか』です。

ES Modules 現況

ES2015 が発刊されてそろそろ一年です。 ES2015 にある機能は Node.js v6でも 93% 程度カバーされています。モダンブラウザでも大体が90%を超えています。しかし、 ES Modules だけはまだどのブラウザも実装しきれていません(kangax compat table は ES Modules は省かれてます)。

f:id:yosuke_furukawa:20160509010917p:plain

そもそも ECMAScript 2015 自身で定義されたのは構文だけなので、構文はともかく、どうやってモジュールを取ってくるかという Loader の部分がまだ決まりきっていません。

https://whatwg.github.io/loader/

現時点はいくつも決めなきゃいけないポイントがあって

  • 参照解決処理
  • 取得処理
  • script タグでどう書くのか
  • メモ化処理(所謂caching)

の全てを決めて一旦ロードマップ上のMilestone 0 が達成されるような状況です。

https://github.com/whatwg/loader/blob/master/roadmap.md

scriptタグでどう書くのか、参照解決処理など、ある程度決まっている処理はありますが、どの項目もまだ議論中です(少なくとも github 上ではまだ milestone 0 を discussion している最中に見える)。各種ブラウザでも、実装が始まっているところはありますが、仕様の方針待ちなところが多いです。

なんで Node.js に ES Modules が必要なのか

ES Modules の仕様が定義されるよりも前に Node.js は CommonJS と呼ばれるモジュールシステムを採用しました*1。それと npm というパッケージマネージャの組み合わせでエコシステムを作っています。結果として npm のエコシステムは Node.js にとどまらず、Browserify や webpack を組み合わせてフロントエンドにとっても大きなエコシステムになっています。

『CommonJS で既に育ってしまった生態系の中で ES Modules という標準仕様とどうやって相互運用性(interoperability)を取るのか』 これが ES Modules が定義され始めた最初からずっと Node.js / npm で語られてる事でした。

相互運用性がないとこれまでのエコシステムと乖離(friction)ができてしまいます。せっかく Browserify や webpack で埋めたfrontend browserとNode.js との乖離がこれでまた起きることになります。

Node.js ではじゃあどうしようとしているのか

これではイカン、という事で Bradley Meck 氏が interop を取ろうと Proposal を書き起こしました。最初に Proposal を書いた時は議論がいくつもあったので ものすごくたくさんの話が巻き起こってまとまらなかった のですが、何度も何度も議論を重ねて今やっと DRAFT というステータスになっています。

node-eps/002-es6-modules.md at master · nodejs/node-eps · GitHub

一応言っておくと DRAFT というのはやると決めた訳じゃないです。議論のテーブルに乗った状態DRAFT です。ステータスとしては DRAFT => ACCEPTDRAFT => REJECT の2通りがあるので REJECT されて無かったことになる可能性もあります。

ES Modules on Node.js 概要

おおまかな解決アルゴリズムを記述します。

まず、 DynamicModuleRecord と呼ばれる CommonJS 用の module 置き場を定義します。これは ES Modules から CommonJS の module.exports で定義されたものを import で読み込めるようにするためのレジストリです。

その上で下記のアルゴリズムで読み込みます。

1.  読み込もうとしているファイルが CommonJS で定義されているのか ES Modules で定義されているのかを確認する(※)
2. もし CommonJS なら
  2-1. ファイルを即時評価する(今まで通り)
  2-2. DynamicModuleRecord に `module.exports` で読み込んだものを入れる
3. もし ES Modules なら
  3-1. ファイルをパースする(import/export でファイルを取得して、bindingを作るため)
  3-2. 再帰的に全ての依存関係のあるファイルを持ってくる
  3-3. 全ての依存関係のファイルから `import`  の binding を作る
  3-4. 評価する

簡易フローチャートで書くとこうですね。

f:id:yosuke_furukawa:20160509230807p:plain

この後さらにケースとしてはファイルが循環参照されてたらどうするかとかの話がありますが、一旦そこは置いておきます。

読み込もうとしているファイルが CommonJS で定義されているのか ES Modules で定義されているのかを確認する ここが今のところ最大の議論のポイントです。

CommonJS なのか ES Modules なのかの確認方法ですが、読み込もうとしているファイルが .mjs拡張子だったら ES Modules、それ以外の .js 等であれば普通に CommonJS として判断しようとしています。

つまり、 CommonJS でも ES Modules でも両方共読み込ませたいモジュールを作る場合、 package.json に下記のように記述し、

{
  "name": "test",
  "version": "0.0.1",
  "description": "",
  "main": "./index", // 拡張子なしで定義する
}

index.mjsindex.js を定義します、片方には ES Modules 形式で書きます。

// index.mjs
export default class foo {
  //..
}

もう片方には CommonJS 形式で書きます。

// index.js
class foo {
  // ...
}
module.exports = foo;

こうすると読み込む側が .mjs 形式に対応している Node.js であれば、 先に .mjs で解決しに行きます。見つからなければ .js の方を解決する、という動きになります。

import で書く場合の path 解決方式

本筋からはそれますが、 import の重要なポイントなので記載しておきます。 ES Modules では Node.js が暗黙的にやっているようなスマートなパスの解決をしてくれない(現時点のローダーでは)ので気をつけましょう。

例えば、 require で書いた場合、 require('./foo') のように .js を削除して記載することが可能でした。

// ./foo.js を解決する
require('./foo');

import でモジュール参照解決をする場合、ES Modules の仕様としては暗黙的に .js を保管してくれたりしないので気をつけましょう。

// ./foo だけ参照解決する
// ./foo.js や ./foo.mjs や ./foo/index.js は参照解決しない
import './foo';

./foo のようにローカルパス付きで読み込む場合は必ず .js もしくは .mjs のように拡張子を付けて参照解決させる事になるでしょう。

import './foo.js';
import './bar.mjs';

ES Modules => CJS

これまでの説明だけでも分かりにくいと思うので例を上げて説明していきます。ここでは ES Modules から CommonJS で定義されたモジュールを読み込む場合です。ES Modules から CJS を「名前付きで」読み込んだ場合、 default というプロパティが入ります(これめっちゃ分かりにくい)。

// cjs.js
module.exports = {
  default:'my-default',
  thing:'stuff'
};
// es.mjs

// 名前付き(as baz)で ./cjs.js のファイルを import する
// bindings なので中の値は外から書き換えられない。
import * as baz from './cjs.js';
// baz = {
//   get default() {return module.exports;},
//   get thing() {return this.default.thing}.bind(baz)
// }
// console.log(baz.default.default); // my-default

// default のオブジェクトを import して foo にアサインする
import foo from './cjs.js';
// foo = {default:'my-default', thing:'stuff'};

// default プロパティを明示して読み込む
import {default as bar} from './cjs.js';
// bar = {default:'my-default', thing:'stuff'};

値を export して、 default の値としてアサインされる例:

// cjs.js
module.exports = null;
// es.mjs
import foo from './cjs.js';
// foo = null;

import * as bar from './cjs.js';
// bar = {default:null};

関数を export する例:

// cjs.js
module.exports = function two() {
  return 2;
};
// es.mjs
import foo from './cjs.js';
foo(); // 2

import * as bar from './cjs.js';
bar.name; // 'two' (関数名が取れる)
bar.default(); // 2 (default 関数に assign される)
bar(); // throws, bar is not a function

CJS => ES Modules

反対に CommonJS から ES Modules を読み込む時は下記のようになります。こちらは export default で export した場合は .default プロパティにアサインされます。

export default を利用する例:

// es.mjs
let foo = {bar:'my-default'};
// note:
export default foo;
foo = null; // これは import 側に影響しない、 export した時点の値が返る、何故なら binding じゃなくて値だから
// cjs.js
const es_namespace = require('./es');
// es_namespace ~= {
//   get default() {
//     return result_from_evaluating_foo;
//   }
// }
console.log(es_namespace.default);
// {bar:'my-default'}

export を利用する例:

// es.mjs
export let foo = {bar:'my-default'};
export {foo as bar};
export function f() {};
export class c {};
// cjs.js
const es_namespace = require('./es');
// es_namespace ~= {
//   get foo() {return foo;}
//   get bar() {return foo;}
//   get f() {return f;}
//   get c() {return c;}
// }

今のところの議論

ちょうど今盛り上がってるのには理由があって、仕様が DRAFT になって議論が始まった後に新しく Counter Proposal (反対提案) が書かれました。それが defense of dot js という Proposal です。

これは .mjs という拡張子で解決するのではなく、 package.json にフィールドを足すだけで解決させるようにしたいという Proposal です。

defense of dot js の内容

こちらの仕様では、基本的に完全な互換性を取るのは諦め、 ES Modules で読み込むことをベースとします。 package.jsonmain フィールドがある時だけはすべてのファイルが CommonJS で読み込まれます。これが基本的な仕様です。

明示的に ES Modules で読み込ませたければ package.jsonmodule フィールドでエントリーポイントを書きます。

// package.json
{
  "main": "index.js",
  "module": "module.js"
}

こうすると、 module フィールドがあれば Node.js は ES Module としてエントリポイントを見に行きます。古いバージョンの Node.js は main フィールドのエントリポイントを見るだけなので古いバージョンにも対応されます。

しかし、このやり方には問題が1つあります。 module 以外のエントリポイントを require から指定できません。例えば、 lodash とかでよく見る require('lodash/array') みたいな読み込み方ができません。そこでこれを解決するために modules.root というフィールドを利用します。

// package.json
{
  "main": "index.js",
  "module": "module.js",
  "modules.root": "lib"
}

上記のように"modules.root": "lib" フィールドがあると lib/* 以下を require から読み込めるようになります。つまり、 ES Modules で書いてあっても require('lodash/array') みたいな書き方ができるようになり、ある程度互換性を保てるようになります。

とはいえ、新しいバージョンで mainmodule も無い package.json では暗黙的には必ず ES Modules になってしまうので、かなり breaking changes です、その代わり拡張子での解決は要らないので、 .mjs などの拡張子を検討する必要はありません。なので、 "Defense of dot js" なわけです。

CommonJS と ES Modules 両方対応するなら?

基本的には ES Modules に傾けるのがこの仕様のポイントですが、人気のあるモジュールはそうはいきません。 ES Modules と CommonJS の両対応させる必要のあるモジュールは存在するでしょう。この時は諦めて transpile して、 ES Modules => CommonJS のファイルも用意しておきます。 transpile した JavaScript も一緒に package に入れておきます。 main フィールドと module フィールドを書いておけば古い Node.js と新しい Node.js で読み込み先を変えてくれます。

Bradley Meck仕様との違い

Defense of dot js 側は将来的に ES Modules に全て揃えよう という姿勢です。互換性をある程度損なっているし、それが起こす混乱はある程度受け入れる考えです。それに対して Bradley Meck 氏の仕様は互換性重視です。あくまで今のCommonJSと相互運用性を取るというのを主軸に添えて語られています。拡張子で ES ModulesなのかCommonJSなのかが変わるというのは言い換えれば一つ一つのファイル単位で ModuleなのかCommonJSなのかを切り替えられる柔軟な仕様です。過渡期は .mjs と .js が混じるかもしれませんが、将来的にユーザーの判断でどっちがデファクトになるかによっては .mjs だけ残る可能性はあります。

hard choice (.mjs vs package.json)

これに対してさらに Counter で Bradley Meck 氏はブログを書いています。

medium.com

なんで .mjs を選んだのか、という理由が書いてあります。 ブログの基本的な論調としてはみんな .js という拡張子に頼りすぎているという話です。

JavaScript には様々な"方言" があります。CommonJS, UMD, AMD、これらの全ての JavaScript は全て .js になってます。

ES Modules というのはもうそれ単体で評価可能な Script ではないし、パースして他のファイルをロードしてチェックするという処理が必要な以上、もういっそ拡張子ごと変えるというアイデアも分からなくはないです。しかも Module だと暗黙的に strict mode で動くので、普通のScript とは別物だと思ったほうがいいです。

他の言語の例を挙げるなら、 .plPerl スクリプト) と .pmPerl モジュール)のように拡張子を変える事を是とする文化もあります。また、ファイルを開く前に拡張子だけ見れば Module なのか Script なのかが分かるので、人間にとっても意味はあります。

この仕様はまだまだ議論中です。また今週の TSC ミーティングで議論があるでしょう。先週もありましたが、話はまとまりきらずに終わりました。今のうちに何かこうしたいという意志があれば issuePR に書くことをおすすめします。

まとめ

  • ES Modules の現時点の状況
  • ES Modules を Node.js はどうするのか
  • ES Modules on Node.js Proposalの詳細
  • Counter Proposal である Defense of dot js の話

*1:(正確には CommonJS の仕様からは大分外れてます。今やあれが CommonJS という事になっちゃってますが・・・)

Node.js v6.0 (Current) がリリースされました。

さて、とうとう皆さん待望の Node.js v6.0 がリリースされました!次のLTS候補です。LTSになるのは2016年の10月からの予定です。v6 の LTS 期間は明示化されてないですが、ルールに照らし合わせれば、LTSになってから 2年半がサポート期間なので、おそらく 2019年4月まではサポートされます。

Node v6.0.0 (Current) | Node.js

Node.js v6.0 の主な変更点

  • ES2015 support の改善
  • module load性能の改善
  • Buffer API の new Buffer() コンストラクタの廃止 (セキュリティ上の理由から)

ES2015 support の改善

やっぱりこれが一番大きな変化ですね。

node.green を見てもらえればわかるかもしれませんが、 ES2015 のサポートがこれまでは 58% だったのが 96% まで大幅に拡大されました。

f:id:yosuke_furukawa:20160427021442p:plain

細かいところはnode.greenを見てもらうとして、いくつかのデフォルトで有効になった機能を紹介します。

デフォルトパラメータ

これは、関数に引数を渡す際に渡されない引数(undefinedな引数)にはデフォルトで特定の値にしてもらう、という機能です

function foo(a = 1, b = 2) {
  return a === 3 && b === 2;
}

foo(3) // true
// 引数の値をデフォルト引数の値として使うことも可能
function f(list, indexA = 0, indexB = list.length) {
  return [list, indexA, indexB];
}
console.log(f([1,2,3]); // [1,2,3], 0, 3
console.log(f([1,2,3],1); // [1,2,3], 1, 3
console.log(f([1,2,3],1,2); // [1,2,3], 1, 2

デフォルトパラメータが書けるようになったので、いままでやっていたような もしも引数 a がundefinedだったらデフォルトで値をセットする という処理が読みやすく、書きやすくなりました。

デストラクチャ

デストラクチャリング、和訳すると分配束縛と呼ばれる機能です。Clojureにある機能ですね。 これを利用すると配列やオブジェクトで設定した値を取り出しやすくなります。 一番良く使うのは値をswapさせる時かと思います。

具体的には以下のとおり。

var hoge = 123;
var fuga =456;

// 値をswapする
var [fuga, hoge] = [hoge, fuga];

console.log(hoge); // 456
console.log(fuga); // 123

var [a, [b], [c], d] = ['hello', [', ', 'junk'], ['world']];

console.log(a + b + c); //hello, world (aに"hello", bに",", cに"world"が入ってる )

var pt = {x: 123, y: 444};
var {x, y} = pt;
console.log(x, y); // 123 444

Rest パラメータ

可変長パラメータを持つ関数を作る時に arguments を使わずに作れるようになりました。

// ...itemsでRestパラメータ
function push(array, ...items) {
  // それをarrayにpush (ここはspread operator)
  array.push(...items);
}
var list = [1, 2, 3];
//list変数に数字をpush
push(list, 4, 5, 6);
console.log(list); //[1, 2, 3, 4, 5, 6]

正規表現に sticky option と unicode option が付く

sticky option は直前に実行した正規表現のlastindexを覚えておき、次に検索する時はその lastindex から検索するというオプションです。

var text = "First line\nsecond line";
var regex = /(\S+) line\n?/y;

var match = regex.exec(text);
console.log(match[1]);  // "First"
console.log(regex.lastIndex); // 11

var match2 = regex.exec(text);
console.log(match2[1]); // "Second"
console.log(regex.lastIndex); // 22

unicode option は正規表現のマッチ時にユニコードリテラルを使って書けるようになったり、サロゲートペアにマッチできるようになるためのフラグです。

"𠮷".match(/^.$/u)[0].length === 2

Proxy API

Proxyが提供してくれるのは、"ちゃんとした" メタプログラミングです。Proxyに関しては、Brendan Eich の構想を描いた発表資料があります。

www.slideshare.net

これが 2010 年という事で、Node.jsが流行りはじめたくらいに提案されたというのが歴史の深さを物語っていますが、Proxyは割りと色んな事ができるAPIです。5年経て、上のスライドで紹介されているものとは API が異なりますが、以下のことに使えます。

  • Getter/Setter への インジェクションを行うことで、プロパティの変更や参照をされた時に処理を変えることができる。
  • method_missing みたいな存在しないメソッドを呼び出した時に呼ばれるメソッドを定義できる。

などなど、名前の通り、代理オブジェクトとして呼び出されたときの処理を肩代わりすることができます。

Proxy API で Getter/Setter にインジェクトする。

こんな感じのことができます。

var handler = {
    get: function(target, name){
        return name in target?
            target[name] :
            37;
    }
};

var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37

存在しないプロパティを呼び出した時のデフォルトの振る舞いを定義できる。

const obj = {abc: 123};
const PropertyChecker = new Proxy(obj, {
  get(target, propKey, receiver) {
    if (!(propKey in target)) {
      throw new ReferenceError('Unknown property: '+propKey);
    }
    return Reflect.get(target, propKey, receiver);
  }
});
console.log(PropertyChecker.abc); // 123
console.log(PropertyChecker.def); // Reference Error

これをうまく応用することで例えば method_missing 的な存在しないメソッドがあった時の振る舞いを定義できます。

Reflect API

一方で Reflect API は Proxy API と対になって使われることが多い API で、 Proxy が処理にインジェクトして、代理オブジェクトとして振る舞うのに対して、 Reflect API はそれのユーティリティオブジェクトで、対象となるオブジェクトに対して処理を反映(Reflect)させる動きをします。

最初にReflectを僕が知った時は対象となるオブジェクトが取れるならそれを直接変更すればいいので、いまいち使いドコロが分かってなかったんですが、ある程度使ってみると使い所が分かってきました。

使い所 その1 演算子じゃなくて、関数にしたい時

in 演算子を考えてみましょう

'assign' in Object // Object のプロパティに `assign` があるかどうか

これは演算子を使った式です、Reflect を使うと下記のように書くことができます。

Reflect.has(Object, 'assign'); // true

演算子じゃなくて関数で表現されているのがわかります。

他にも delete 演算子を Reflect を使って書き換えることが可能です。

// delete 演算子
var a = {abc: '123', def: '456'};
delete a['abc']; // {def: '456'}
// Reflectを使った場合
var a = {abc: '123', def: '456'};
Reflect.deleteProperty(a, 'abc'); // {def: '456'}

専用の演算子を使ったほうが短く書けますが、関数を使って代用できるようにしておくと読みやすさや反映する対象がわかりやすくなります。

使い所その2 例外よりも戻り値として扱いたい時

Object.defineProperty というObjectに対してプロパティを定義する専用の関数がありますが、これは defineProperty に失敗すると例外がthrowされます。そのため下記のように書かなくてはいけません。

try {
  Object.defineProperty(obj, name, desc);
  // 成功時の処理
} catch (e) {
  // 失敗時
}

Reflectができるようになると下記のように書けます

if (Reflect.defineProperty(obj, name, desc)) {
  // 成功時の処理
} else {
  // 失敗時の処理
}

--es_staging flag で有効になるもの

--es_staging flag を付けるとES2015の機能がさらに増えます。ただし、 --es_staging flag はまだ unstable の状態の機能を試すのに使うためのフラグなのであまり本番で積極的に使うものではありません。

末尾再帰呼び出し最適化

再帰呼び出しをした時に再起かどうかを内部的に検知して、再帰呼び出しを普通のループに変換します。 詳しくは下記の teppeis さんのブログが参考になります。

teppeis.hatenablog.com

そこから持ってきた下記のスクリプトで試します。

'use strict'; // 今のところ strict mode でのみ有効
function factorial(n, acc) {
  if (n <= 1) return acc;
  return factorial(n - 1, n * acc);
}

[0,1,2,3,4,5,10,100,1000,10000,100000].forEach(function(n) {console.log(n, factorial(n, 1))});

階上計算処理ですが、これを普通に実行すると、 100000 の所で stack size オーバーフローでエラーになります。

$ node fact.js

0 1
1 1
2 2
3 6
4 24
5 120
10 3628800
100 9.332621544394418e+157
1000 Infinity
10000 Infinity
/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:2
function factorial(n, acc) {
                  ^

RangeError: Maximum call stack size exceeded
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:2:19)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)
    at factorial (/Users/yosuke/go/src/github.com/yosuke-furukawa/node/fact.js:4:10)

しかし、 --es_staging で実行すると通るようになります。

$ node --es_staging fact.js

0 1
1 1
2 2
3 6
4 24
5 120
10 3628800
100 9.332621544394418e+157
1000 Infinity
10000 Infinity
100000 Infinity

Function#name

今までは無名関数だと .name プロパティから関数名を取れませんでした、これが よくある無名関数を左辺に代入する書き方だと問題がありました。

// function.js
var abc = () => {};
const def = function(){};
console.log(abc.name); // abc
console.log(def.name); // def

// ただし、この場合は 普通に名前付き関数の名前が採用される

let ghi = funciton jkl() {};
console.log(ghi.name); //jkl
$ node function.js


jkl

これを --es_staging を付けると下記のようになります。

$ node --es_staging function.js
abc
def
jkl

逆に有効になっていないもの

一番有名所としては import/export でしょうか。 これに関しては、ただいま絶賛議論が紛糾している所です。

ES modules を Node に持ってくる、というのはかなり難しい問題で、今のところまだ有効な打開策が出ていません。そもそもまだ v8 でもパースできないのでパースできるようになったとして、どうやって解決するかという議論が始まったばかりです。

議論のまとめはこちら

github.com

module load 性能の向上

benchmark WG が継続してベンチマークを取るようにしてくれました。

Node.js Benchmarking

benchmark working group では requireや起動時間といった性能を計測するマイクロベンチと acmeairと呼ばれるチケット予約管理アプリを使ったマクロベンチの2種類を実行しています。 v4.x と比較した時に require  した時の性能が初期ロードで 3倍高速に、二回目以降のロード(cache付きロード)で5倍高速になるようになりました。

ops/sec higher is better f:id:yosuke_furukawa:20160427100426p:plain

また acmeair を使った全体のスループットに関しても若干の向上が見られます。

f:id:yosuke_furukawa:20160427101015p:plain

Buffer API の new Buffer() コンストラクタの廃止

セキュリティ上の理由から、 new Buffer() コンストラクタは廃止されました。 詳しくはこの辺りを見てもらうと良いかもしれません。

おまけ

Windows XP/Vista で node.js のサポートが終了しました。

まとめ

他にも色々と変更はありますが、全てを紹介しようとすると膨大な量なので一旦ここまでに停めておきます、すべての変更をちゃんと追いたい人は以下のChangelog を参考にしてください。

node/CHANGELOG.md at master · nodejs/node · GitHub

アップグレードするかどうか

まず v0.10 / v0.12 を使っている場合は今年の年末でサポートが切れてしまうので v4 もしくは v6 への upgradeを推奨します。

f:id:yosuke_furukawa:20160427102953p:plain

v4 を使っているユーザーは 2018年までサポートは続くのでまだアップグレードしなくても構いません、とはいえ上にあげたような新しい機能を使いたいユーザーはアップグレードを検討してください。

v5 を使っているユーザーはあと2ヶ月はサポートされますが、v5はLTS対象じゃないので、アップグレードを推奨します。v6 にアップグレードすることを検討してください。

Stable ラベルから Current ラベルへ

今までは Stable というラベルが最新のバージョンにはついていましたが、 LTS と混同されやすいのでラベル名が Current に変わりました。v6がLTSになったらその時はおそらく LTS ラベルが付き、 v7 が Current へと変わります。

v7 のリリースもまだ明示化されてないですが、今のところの計画では今から半年後の2016年の10月には次のv7.0がリリースされる予定です。

まとめ

Node.js v6.0 がリリースされました。

  • 主な変更点
  • ES2015 サポート拡充
  • 性能向上
  • new Buffer API の廃止
  • アップグレード検討有無
  • Stable から Current へ

という話をしました。