第23回 #tokyoclj 参加報告

イベント概要

これです。CA良いビルだった。
初回ピックアップに間に合わなかったので、近くのモリバコーヒーでClojure環境を整備して、1時間遅れでの参加でした。

やったこと

環境構築

一緒に参加したcircularuinsさんに教えてもらいつつ、EmacsにCIDER環境を設定。
MacへのJDKやLeiningenのインストールは完了していたので、すぐ終わりました。

$ lein -v
Leiningen 2.5.1 on Java 1.8.0_05 Java HotSpot(TM) 64-Bit Server VM

EmacsのCIDERでClojureのREPLに入るには、まずLeiningen新しいプロジェクトを作って、そこに入ってからcider-jack-inをするらしい。
...のですが、結局ciderは使いませんでした。詳細は後述。

Om

オームと呼びます。これを触りたくてTokyo.cljに参加したようなものです。

まず、Clojureでwebアプリを作るフレームワークがあります。Luminusなどです。(Luminusは、正確にはwebアプリ開発に必要なライブラリの集合です)
それに関連して、JSにコンパイルできるClojureScriptというものがあります。
そして、ClojureScriptから今話題のReact.jsを使うためのインタフェースが、Omです。

「ClojureScriptからReact.jsを使うOm」が、今話題らしいです。
ClojureScript内では変数の上書きができないのですが、その制約がReact.js(というかFlex??)を使う上で"いい感じにマッチする"らしいです。
なんとなーくでは良さそうな感じがしますが、良さを具体的にわかっていないので、まず触ってみよう!というのが動機でした。

まず、Luminusアプリを作ります。

$ lein new luminus cljsapp +cljs
Generating a lovely new Luminus project named cljsapp...

Leiningenで新しいプロジェクトを作る際に、Luminusテンプレートと+cljsフラグを付けます。

$ cd cljsapp; tree
.
├── Procfile
├── README.md
├── env
│   ├── dev
│   │   └── cljs
│   │       └── cljsapp
│   │           └── dev.cljs
│   └── prod
│       └── cljs
│           └── cljsapp
│               └── prod.cljs
├── project.clj
├── resources
│   ├── public
│   │   ├── css
│   │   │   └── screen.css
│   │   ├── fonts
│   │   │   ├── glyphicons-halflings-regular.eot
│   │   │   ├── glyphicons-halflings-regular.svg
│   │   │   ├── glyphicons-halflings-regular.ttf
│   │   │   └── glyphicons-halflings-regular.woff
│   │   ├── img
│   │   ├── js
│   │   └── md
│   │       └── docs.md
│   └── templates
│       └── app.html
├── src
│   └── cljsapp
│       ├── handler.clj
│       ├── layout.clj
│       ├── middleware.clj
│       ├── repl.clj
│       ├── routes
│       │   └── home.clj
│       ├── session_manager.clj
│       └── util.clj
├── src-cljs
│   └── cljsapp
│       └── core.cljs
└── test
    └── cljsapp
        └── test
            └── handler.clj

23 directories, 21 files

ここで一旦、アプリを起動してみます。

➜  cljsapp  lein ring server
2015-2-22 11:59:11 +0900 yuukigoodman-pc INFO [cljsapp.handler] -
-=[ cljsapp started successfully using the development profile ]=-
2015-02-22 11:59:11.289:INFO:oejs.Server:jetty-7.6.13.v20130916
2015-02-22 11:59:11.397:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:3000
Started server on port 3000

Railsと比べても起動に時間がかかって心配になるし、アプリが起動すると勝手にブラウザがページを開くのでびっくりします。

f:id:yuukigoodman:20150222120137p:plain

めっちゃbootstrapな感じです。

次に、ClojureScriptをJSにコンパイルしてみます。

$ lein cljsbuild once
Compiling ClojureScript.
Compiling "resources/public/js/app.js" from ("src-cljs" "env/dev/cljs")...
Successfully compiled "resources/public/js/app.js" in 16.713 seconds.

treeするとたくさん表示されるので割愛。

毎回コンパイルするのは面倒なので、開発時はオートコンパイルを実行しておきます。

$ lein cljsbuild auto
Compiling ClojureScript.

ここでcljsファイルを変更すると、勝手にコンパイルしてくれるので良い感じです。

src-cljs/cljsapp/core.cljsを以下のように変更 f:id:yuukigoodman:20150222121059p:plain

保存するとコンパイルが走ります。

$ lein cljsbuild auto
Compiling ClojureScript.
Compiling "resources/public/js/app.js" from ("src-cljs" "env/dev/cljs")...
Successfully compiled "resources/public/js/app.js" in 7.737 seconds.

でも相変わらず時間がかかっている点は良くない感じです。

そして、いよいよOmを追加します。

diff --git a/src-cljs/cljsapp/core.cljs b/src-cljs/cljsapp/core.cljs
index d7554dd..91ea902 100644
--- a/src-cljs/cljsapp/core.cljs
+++ b/src-cljs/cljsapp/core.cljs
@@ -2,7 +2,9 @@
   (:require [reagent.core :as reagent :refer [atom]]
             [secretary.core :as secretary]
             [reagent-forms.core :refer [bind-fields]]
-            [ajax.core :refer [POST]])
+            [ajax.core :refer [POST]]
+            [org.omcljs/om "0.8.8"]
+            )
   (:require-macros [secretary.core :refer [defroute]]))

 (def state (atom {:saved? false}))

デフォで生成されるテンプレートを削除します。resources/templates/app.htmlです。
こうなります。

<html>
  <head>
      <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>Welcome to cljsapp</title>
  </head>
  <body>
    {% if dev %}
      <script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.2/react.js"></script>
      {% script "/js/out/goog/base.js" %}
      {% script "/js/app.js" %}
      <script type="text/javascript">goog.require("cljsapp.app");</script>
    {% else %}
      <script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.2/react.min.js"></script>
      {% script "/js/app.js" %}
    {% endif %}
  </body>
</html>

何も表示されません。

ここに、React.jsで文字を表示するdivタグを作っておきます。

diff --git a/resources/templates/app.html b/resources/templates/app.html
index 2f52996..8e97d61 100644
--- a/resources/templates/app.html
+++ b/resources/templates/app.html
@@ -4,6 +4,7 @@
       <title>Welcome to cljsapp</title>
   </head>
   <body>
+    <div id="app"></div>
     {% if dev %}
       <script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.2/react.js"></script>
       {% script "/js/out/goog/base.js" %}

そして、clojurescriptです。

diff --git a/project.clj b/project.clj
index 21ba32b..56f99ab 100644
--- a/project.clj
+++ b/project.clj
@@ -20,7 +20,8 @@
    [environ "1.0.0"]
    [ring-server "0.3.1"]
    [reagent-forms "0.2.9"]
-   [secretary "1.2.1"]]
+   [secretary "1.2.1"]
+   [org.omcljs/om "0.8.8"]]
   :repl-options
   {:init-ns cljsapp.repl}
   :jvm-opts
diff --git a/src-cljs/cljsapp/core.cljs b/src-cljs/cljsapp/core.cljs
index 91ea902..2f353eb 100644
--- a/src-cljs/cljsapp/core.cljs
+++ b/src-cljs/cljsapp/core.cljs
@@ -3,83 +3,17 @@
             [secretary.core :as secretary]
             [reagent-forms.core :refer [bind-fields]]
             [ajax.core :refer [POST]]
-            [org.omcljs/om "0.8.8"]
+            [om.core :as om :include-macros true]
+            [om.dom :as dom :include-macros true]
             )
   (:require-macros [secretary.core :refer [defroute]]))

core.cljsはデフォで生成される部分がたくさんあるのですが、テンプレートの削除に伴って不要になるので、消しておきます。 ここで、lein ring serverとlein cljsbuild onceで、Omが使用可能になっていることを確認しておきます。(注: 僕はまだここらへんの理解が浅いです。)
コンパイルがうまくいくようなら、いよいよさっきのdivタグに文字を表示させます。

(def app-state (atom {:text "Hello, ClojureScript!!"}))

(om/root
 (fn [app owner]
   (reify om/IRender
     (render [_]
       (dom/h1 nil (:text app)))))
 app-state
 {:target (. js/document (getElementById "app"))})

src-cljs/cljsapp/core.cljsに↑を追記します。
これでコンパイルとringの起動ができていれば、以下のようにブラウザに表示されるはずです。 f:id:yuukigoodman:20150222130429p:plain

懇親会

非常に楽しかったです。

  • Clojureでニューラルネットワークの話
  • Datomicの話
  • Source Code Readingの話
  • Tokyo.cljのSlackを用意する話
  • RasPiでClojureの話

個人的には、Datomicがアツいです。
Clojureの一部がClojureで実装されていたりするので、その2つのSCRをやったら面白そう。
あわせて4Clojureとかで勉強したり、今回の成果のLuminus + Omでアプリを作ったりしていきたいです。

次回開催は5月くらいらしいです。