Reactのリアクティブとコンポーネント指向の考えはすごく良いのですが、どうも書き方に馴染めません。IsomorphicもJavaScriptで書くよりClojureで書く方が楽しいのでReagentを使っています。Node.jsのES6時代に向けたKoaのIsomorphicを調べていると、horseやDekuといったライブラリがありました。今回はDekuの方を試してみます。
Deku
DekuはReactのalternativeとしてUIのコンポーネントを作成するライブラリです。
NIHではない
なぜDekuを開発し始めたかはDeku: How we built our functional alternative to Reactに書いてあります。頭が痛いすぐ内製でやりたがるNIHではないと言っています。彼らはフロントエンドのパッケージマネージャとしてDuoを使っているようです。Reactのような大きなブラックボックス中でたくさんの機能を実装するよりも、小さなモジュールで構成した方が見通しもよく、デバッグしやすいといった考え方が背景にあります。見通しがよく何か問題があったときに原因を特定しやすいというのはフレームワークを選ぶ上でとても重要なことです。
IsomorphicかAPIサーバーか
以前Reagent入門 - Part3: クライアントとサーバーの通信パターンやReagent入門 - Part4: SPAとフォームの要件で考察しました。今のところSPAはIsomorphicでなくAPIサーバーにして、毎回面倒ですがルーティングやモデルはクライアントもサーバーも2回書くのがよいと思っています。
Isomorphic初心者なので、Clojure/ClojureScriptで書いていてもサーバーのコードを書いているのかクライアントなのか時々わからなくなります。ルーティングを書いているときなどほとんど同じコードなので混乱してしまいます。
プロジェクト
今回のプロジェクトは以下の構成です。Dekuとサンプルのtodomvcを読みながらインストールとKoaを使ったサーバサイドレンダリングを試してみます。
Dekuのビルド方法
Dekuはクライアントサイドのライブラリです。ES6で書くのでいずれにいてもBabelは必要です。
Browserfify
Browserfifyを使うのが、サーバーサイドとクライアントサイドのどちらのレンダリングを使う場合でも一番簡単なようです。babelifyを使うとJSXのコンパイルも簡単にできます。
$ browserify -t babelify main.js > build.js |
Duo
Duoは次世代のフロントエンドのパッケージマネージャです。DuoからBabelを使うときにはduo-babelが必要になります。DekuはDuoを推しているようなので使ってみようと思います。
Duoの考え方は1つのパッケージは1つの機能を提供することです。コード上のインポートは直接GitHubのパッケージを指定してます。
import {element,tree,render} from 'segmentio/deku@0.2.1' |
ES6で書いてBabelが必要になるので、duoコマンドには--use duo-babel
フラグを付けてコンパイルして使います。
$ duo --use duo-babel main.js > build.js |
babel/register
単純なHello Worldなので、今回はindex.jsでbabel/register
のフックからrequireしたapp.es6を自動的にコンパイルします。本来のIsomorphicならばクライアント側のES6コードはbrowserify
でコンパイルして、ES5
にビルド済みのjsファイルをindex.htmlなどから<script src="/build/index.js"></script>
として最初にロードする必要があります。次回はクライアント側のbrowserify
を試してみます。
プロジェクト
適当なディレクトリにプロジェクトを作成します。リポジトリはこちらです。
$ cd ~/node_apps/docker-deku-koa |
Dockerfileとdocker-compose.yml
Dockerfileのベースイメージはiojsを使います。
FROM iojs:2.3 |
docker-compose.ymlではDockerホストのカレントディレクトリごと、コンテナのWORKDIR
である/app
にマウントします。
deku: |
コンテナにマウントしたときにnode_modules
が隠れないように、カレントディレクトリに予めシムリンクを作っておきます。
$ ln -s /dist/node_modules . |
package.json
package.jsonに必要なパッケージをdependenciesに追加します。
{ |
サーバーサイド
babel/register
のフックでapp.es6
をrequireしたときに自動的にES5にコンパイルします。jsxPragma
オプションにelement
を指定しています。こうするとJSXの変換にBabelがデフォルトのReact.createElementの代わりに、import {element} from 'deku'
のelementを使うようになります。
; |
app.es6はES6で書いたKoaのコードです。IsomorphicなKoaのテストなので、クライアントサイドのコードをimportしてレンダリングしています。
|
クライアントサイド
client/helloworld.es6
で、サーバーサイドのserver/app.es6
でも使うHelloWorld
コンポーネントを定義しています。
|
Dockerイメージのビルドと起動Docker
$ cd ~/node_apps/docker-deku-koa |
Dockerホストの3030ポートにマップされています。curlコマンドでテストするとHello World!のdiv要素が返りました。
$ curl localhost:3030 |