Arantium Maestum

プログラミング、囲碁、読書の話題

Clojure Web Development勉強 - ClojureScript(その4)figwheelの最小限設定

Figwheelは素晴らしい。FigwheelはClojureScriptを使うことで得る大きな喜びの一つだ。

と過剰に思われる売り込みで始める。しかし、個人的には全く誇張している意識はない。

Figwheelはwebsocketを使って、ソースファイルの変更を自動的にブラウザに反映させる開発ツールである。

前回lein cljsbuild autoでClojureScriptからJavaScriptへのコンパイルを自動化し、ソースファイルを変更して保存すれば自動的にJavaScriptが生成され、そのあとブラウザをリロードすることで変更を反映させることができる、というワークフローを紹介した。

Figwheelはそれをもう一歩進めた形になる。ClojureScriptのソースファイルを変更・保存した時点でブラウザリロードする必要なく自動的にブラウザに新しいJavaScriptがロードされる。

文章で説明しても凄さがいまいち伝わらない感があるが、動画で見た時は相当な衝撃を受けたのを覚えている。見たのはfigwheelの開発者Bruce Haumanによる紹介動画:

www.youtube.com

そして実際に使うとさらに感動する。「cljsbuildから一歩進んだ」というのは正しいが、その一歩がいかに重要かを充分伝えきれていないと思う。

まず、エディタから離れることなくブラウザで変更が確認できる。私の場合はvimを使っているのだが、:wと叩いた時点でブラウザに反映される。書いては:w、書いては:wでホームポジションから手を離すことなしに開発サイクルが回る。

そしてページリロードをしないことで状態が維持される。リロードした場合ページが初期状態に戻されてしまい、例えばそこから状態を色々変更していた場合、前回と同じ変更を加えていって手動でリロード前の状態に戻す必要が生じる。Figwheelを使うとその必要がなく、コード変更前のページの状態のまま挙動などが変わるのを確認できる。

今回のコード:

gist.github.com

ポイントとなるのは3点。

  • pluginsにlein-figwheelを追加する
  • cljsbuildの:optimizationsがないビルドに:figwheel trueを追加する
  • output-to/output-dirをresources/publicディレクトリのどこかにする

最初の二つはleiningenとcljsbuildにちゃんとfigwheelと連動するよう伝えるオプション。

三つ目のポイントは、figwheelが自動的に立ち上げてくれるローカルサーバがデフォルトでresources/pubicをルートディレクトリにしているので、サーバからアクセスするファイルはhtmlであれjavascriptであれすべてresources/publicの下位ディレクトリ(あるいはresources/public内)になくてはいけない。

これでlein figwheelとコマンドを走らせると

Figwheel: Cutting some fruit, just a sec ...
Figwheel: Validating the configuration found in project.clj
Figwheel: Configuration Valid :)
Figwheel: Starting server at http://0.0.0.0:3449
Figwheel: Watching build - dev
Figwheel: Cleaning build - dev
Compiling "resources/public/js/main.js" from ["src"]...
Successfully compiled "resources/public/js/main.js" in 11.823 seconds.
Launching ClojureScript REPL for build: dev
Figwheel Controls:
          (stop-autobuild)                ;; stops Figwheel autobuilder
          (start-autobuild [id ...])      ;; starts autobuilder focused on optional ids
          (switch-to-build id ...)        ;; switches autobuilder to different build
          (reset-autobuild)               ;; stops, cleans, and starts autobuilder
          (reload-config)                 ;; reloads build config and resets autobuild
          (build-once [id ...])           ;; builds source one time
          (clean-builds [id ..])          ;; deletes compiled cljs target files
          (print-config [id ...])         ;; prints out build configurations
          (fig-status)                    ;; displays current state of system
  Switch REPL build focus:
          :cljs/quit                      ;; allows you to switch REPL to another build
    Docs: (doc function-name-here)
    Exit: Control+C or :cljs/quit
 Results: Stored in vars *1, *2, *3, *e holds last exception object
Prompt will show when Figwheel connects to your application

こんな感じのメッセージが出力される。

あとはブラウザからlocalhost:3449にアクセスするとindex.htmlが開き、コンパイルされたJavaScriptが走る。

ChromeJavaScriptコンソールなどを立ち上げると

Figwheel: trying to open cljs reload socket  utils.cljs?rel=1478607372893:49
Figwheel: socket connection established  utils.cljs?rel=1478607372893:49

とソケットで通信していることがわかる。

これでcore.cljsをいじって保存してみる。例えば

(ns min-figwheel.core)
(js/alert "Hello ClojureScript!")

(ns min-figwheel.core)
(js/alert "Hello Figwheel!")

に変更してセーブする。それだけで自動的に新しいアラートメッセージがブラウザ上で表示される。

あるいは

(ns min-figwheel.core)
(js/console.log "Hello Figwheel!")

と変更してコンソールを確認すると

Figwheel: notified of file changes  utils.cljs?rel=1478607372893:49
Hello ClojureScript!  core.cljs?rel=1478641111736:2
Figwheel: loaded these files  utils.cljs?rel=1478607372893:49
("../min_figwheel/core.js")  utils.cljs?rel=1478607372893:51 

こんな風に表示される。ちゃんとソースの変更が反映されてコンソール出力できているのがわかる。core.cljsのどこに対応しているのかまで表示していて、リンクをクリックするとソースが確認できるのもなかなか面白い。

さて、今まで恐ろしく簡単なClojureScript機能しか使ってきていないので、Figwheelのありがたみがまだ明確に出てきていない。Figwheelの真価が発揮されるのはClojureScriptで複雑な処理を書き出してからである。特に、FigwheelとDOM操作系のライブラリを合わせることでページをグリグリと非常にインタラクティブに作成できるようになる。

次はClojureScript上でどうやってDOM操作をしていくかという観点からReactについて書きたい。