Luminus テンプレートで Figwheel をもっと便利に使う

Clojure やってる人たちに Web アプリ作るとき何使ってます?と聞くと結構な割合で Luminus テンプレート使ってると返ってきます。
ですが、デフォルトだとあんまり ClojureScript の開発環境が良くない気がするので、 Figwheel をもっと便利に使う設定を紹介します。

ちなみに ClojureScript の開発するなら Chestnut という有名なテンプレートがありますが、幾つかの理由で Chestnut より Luminus を使いたいので今回は Luminus です。

`lein new luminus luminus-app +cljs` を実行してアプリケーションのひな形を作った例を使います。

まず `luminus-app/env/dev/clj/luminus_app/dev.clj` を作成して以下のコードを書きます。

``` clojure
(ns luminus-app.dev
  (:require [clojure.edn :as edn]
            [clojurescript-build.auto :as auto]
            [figwheel-sidecar.auto-builder :as fig-auto]
            [figwheel-sidecar.config :as conf]
            [figwheel-sidecar.core :as fig]))

(defonce fig-server (atom {}))

(defn start-figwheel []
  (let [server (fig/start-server { :css-dirs ["resources/public/css"] })
        builder (fig-auto/autobuild*
                 {:builds [{:id "dev"
                            :source-paths ["src-cljs" "env/dev/cljs"]
                            :compiler {:output-to            "resources/public/js/app.js"
                                       :output-dir           "resources/public/js/out"
                                       :source-map           true
                                       :optimizations        :none
                                       :source-map-timestamp true
                                       :externs ["react/externs/react.js"]}}]
                  :figwheel-server server})]
    (reset! fig-server {:figwheel-server server :cljs-builder builder})))

(defn stop-figwheel []
  (let [server (:figwheel-server @fig-server)
        builder (:cljs-builder @fig-server)]
    (when builder
      (auto/stop-autobuild! builder))
    (when server
      (fig/stop-server server))
    (reset! fig-server {:figwheel-server nil :cljs-builder nil})))
```

次に `project.clj` の `:project/dev` に `:source-paths ["env/dev/clj"]` を足します。そうすると `:project/dev` の部分は以下のようになります。

``` clojure
:project/dev  {:source-paths ["env/dev/clj"] ;; 今回足した部分はココだけ!!
               :dependencies [[ring/ring-mock "0.2.0"]
                              [ring/ring-devel "1.4.0"]
                              [pjstadig/humane-test-output "0.7.0"]
                              [lein-figwheel "0.3.7"]
                              [org.clojure/tools.nrepl "0.2.10"]]
               :plugins [[lein-figwheel "0.3.7"]]
               :cljsbuild
               {:builds
                {:app
                 {:source-paths ["env/dev/cljs"] :compiler {:source-map true}}}}

               :figwheel
               {:resource-paths "resources"
                :http-server-root "public"
                :server-port 3449
                :nrepl-port 7002
                :css-dirs ["resources/public/css"]
                :ring-handler luminus-app.handler/app}

               :repl-options {:init-ns luminus-app.core}
               :injections [(require 'pjstadig.humane-test-output)
                            (pjstadig.humane-test-output/activate!)]
               ;;when :nrepl-port is set the application starts the nREPL server on load
               :env {:dev        true
                     :port       3000
                     :nrepl-port 7000}}
```

さらに `luminus-app/src/luminus_app/handler.clj` の `init` 関数を次のように修正します。

``` clojure
(defn init
  "init will be called once when
   app is deployed as a servlet on
   an app server such as Tomcat
   put any initialization code here"
  []

  (timbre/merge-config!
    {:level     (if (env :dev) :trace :info)
     :appenders {:rotor (rotor/rotor-appender
                          {:path "luminus_app.log"
                           :max-size (* 512 1024)
                           :backlog 10})}})
  (when (env :dev)
    (parser/cache-off!)
    (require 'luminus-app.dev)
    ((resolve 'luminus-app.dev/start-figwheel)))

  (start-nrepl)
  (timbre/info (str
                 "\n-=[luminus-app started successfully"
                 (when (env :dev) " using the development profile")
                 "]=-")))
```

こうすれば開発時にサーバーを起動したタイミングで Figwheel の自動ビルド/リロードが動くようになります。便利ですね。

ちなみに figwheel-sidecar を使えばいいだけなので、別に Luminus テンプレートじゃなくても似たような設定を自力で出来るなら何を使っても同じように設定できます。はい。

See also: [Let’s start ClojureScript with Luminus template and Figwheel / (def ayalog '())](http://ayato-p.github.io/blog/2015/08/03/let_s_start_clojurescript_with_luminus_template.html)