テンプレートを使わずに最小限のClojurescriptプロジェクトを作ってみた

TL;DR
==
`lein new <project-name>`で作成して`lein-cljsbuild`でコンパイルしたClojurescriptプロジェクトがローカルサーバで動くところまで手動でやってみる。

はじめに
==

ClojureやClojurescriptで開発する場合、leiningenを使うのが一般的だと思います。少なくとも私は使います。

leiningenには様々なtemplateが用意されています。`lein new reagent`や`lein new figwheel`とかですね。

これらを使うことによって、使いたいライブラリやツールに必要な基本的なディレクトリ・ファイルの作成や、`project.clj`に記述する必要のある依存関係などを全て自動的に解決してくれます。

ただ、leinテンプレートしか使っていないと、具体的にどのライブラリ・ツールがどんな依存関係でどのディレクトリのどのclj/cljs/html/js/cssファイルと連動しているのか、なかなかわかりません。

というわけで、`lein new <project>`からはじめて、テンプレートを使わずに非常に簡単なClojurescriptプロジェクトを作ってみたいと思います。

ちなみにこの[Introduction to ClojureScript and Reagent](https://www.youtube.com/watch?v=wq6ctyZBb0A)というビデオに大いに触発されています。
I would like to thank Jordan Leigh and Will Piers for a fantastic video that provided the inspiration for this post.


前提条件
==

以下のものがインストールされている必要があります：
1. Clojure
2. Leiningen
3. Python (サーバを走らせるため。他の言語で簡単にローカルホストでサーバを立ち上げられるなら問題なし。2.x、3.xのどちらでもオッケー）

ちなみにOS X El Capitanを使っていますが、これはさほど関係ないはずです。

手順
==
### 1. Leiningenのアップデート

とりあえず`lein upgrade`でleiningenを最新版にしておきましょう。記事を書いている2016年9月の時点で私のマシンでのバージョンは

> Leiningen 2.7.0 on Java 1.8.0_101 Java HotSpot(TM) 64-Bit Server VM

です。

### 2. `lein new <project-name>`

プロジェクトを立ち上げます。この記事ではsample-cljsという名前をつけておきます。ターミナルで

```
lein new sample-cljs
```

と入力すると、以下のような構成のディレクトリが出来上がります。

```
.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── doc
│   └── intro.md
├── project.clj
├── resources
├── src
│   └── sample_cljs
│       └── core.clj
└── test
    └── v1
        └── core_test.clj
```


### 3. `project.clj`にライブラリ・ブラグイン・コンパイル設定を書き込む

`project.clj`を開きます。以下のようになっているかと思います。

```clj
(defproject sample-cljs "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]])
```

まずライブラリの追加です。`:dependencies`のベクタの中にClojurescriptを追加しましょう。[Clojurescriptのgithubページ](https://github.com/clojure/clojurescript)から最新版のLeiningen dependency informationをとってきます。
（現在は`[org.clojure/clojurescript "1.9.229"]`です）

次にClojurescriptをjavascriptにコンパイルするためのプラグインであるlein-cljsbuildを追加します。:dependenciesの下に下記のplugin情報を入れます。

```clj
:plugins [[lein-cljsbuild "1.1.4"]]
```
これも最新版を[githubのプロジェクト](https://github.com/emezeske/lein-cljsbuild)で調べて使ってください。

最後にcljsbuildがコンパイルする際に使う詳細情報を記述していきます。

```clj
:cljsbuild {:builds [{:id "dev"
                      :source-paths ["src"]
                      :compiler
                      {:optimizations :none
                       :output-to "resources/public/javascripts/dev.js"
                       :output-dir "resources/public/javascripts/cljs-dev/"
                       :pretty-print true
                       :source-map true}}]})
```
こちらの情報についての説明は長いので別記事に載せます。
注意点としては`resources/public/javascripts/cljs-dev/`の下層３つのディレクトリは現時点では存在しないので作成する必要があることに気をつけて下さい。

上記３つの変更を加えて、`project.clj`は最終的に以下のようになります。

```clj
(defproject sample-cljs "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [org.clojure/clojurescript "1.9.229"]]
  :plugins [[lein-cljsbuild "1.1.4"]]
  :cljsbuild {:builds [{:id "dev"
                        :source-paths ["src"]
                        :compiler
                        {:optimizations :none
                         :output-to "resources/public/javascripts/dev.js"
                         :output-dir "resources/public/javascripts/cljs-dev/"
                         :pretty-print true
                         :source-map true}}]})
```

### 4. ディレクトリと`resources/public/index.html`作成

先ほど言った通り、`resources`ディレクトリの中に`public/javascripts/cljs-dev/`というディレクトリを作成します。

そして`resources/public/`の中に`index.html`というファイルを作成して、以下のように入力してください。

```html
<html>
  <head>
  </head>
  <body>
    <div id="scripts">
      <script src="./javascripts/cljs-dev/goog/base.js"></script>
      <script src="./javascripts/dev.js"></script>
      <script>goog.require('sample_cljs.core')</script>
    </div>
  </body>
</html>
```

これも長いので説明は別記事で。

```html
<script>goog.require('sample_cljs.core')</script>
```

が`sample-cljs.core`ではない（-が_になっている）というポイントに注意して下さい。

### 5. `core.cljs`を記述

それでは実際にClojurescriptのコードを書いていきましょう。この記事ではjavascript interopを使ってAlertポップアップに文章を表示させるだけに留めます。

まず、現在`src/sample_cljs/`ディレクトリ内にある`core.clj`というClojureファイルを`core.cljs`というClojurescriptファイルに置き換えます。その上で、中身も以下のように変えましょう。

```clj
(ns sample-cljs.core)
(js/alert "Hello clojurescript!")
```

以上です。これでプロジェクトのファイルはすべて用意できました。

### 6. コンパイル

```
lein cljsbuild once dev
```

とシェルで実行してプロジェクトをコンパイルしましょう。

このコマンドは`lein-cljsbuild`を使って、`project.clj`の`:cljsbuild`で`:id "dev"`として指定した設定で、一回(once)プロジェクトをコンパイルする、という意味になります。[^1]

[^1]: 似たようなところで、`core.cljs`に変更を加えたら自動的にコンパイルする`lein cljsbuild auto`というコマンドもあります。

>Compiling ClojureScript...
Compiling "resources/public/javascripts/dev.js" from ["src"]...
Successfully compiled "resources/public/javascripts/dev.js" in 0.994 seconds.

といったメッセージが出てきたならコンパイル完了です。

ちなみにここで私は以下の三種類のミスで失敗したことがあります：
- `core.clj`を`core.cljs`に直していない
- `lein-cljsbuild`のバージョンが古い
- 単なる入力ミス
うまくいかなかった場合はここら辺から確認してみてください。

### 7. サーバを走らせる
あとはローカルサーバを走らせて確認するだけです。

シェルから使えるPythonのバージョンが3.xなら

```
python -m http.server
```

2.xならアップグレード・・・と言いたいところですが

```
python -m SimpleHTTPServer
```

でローカルサーバを立ち上げてください。（他の立ち上げ方でも問題ないはずです）

立ち上がったのが確認できたらブラウザ上で

```
localhost:8000/resources/public/index.html
```

にアクセスして、javascriptアラートで"Hello Clojurescript!"というメッセージがポップアップ表示されれば成功です。（ポートのxxxxはローカルサーバが返してきた数字を入れてください）

![sample-cljs-final.png](https://qiita-image-store.s3.amazonaws.com/0/140768/6d6184b6-8719-4e60-ea89-dba9619b6a3c.png)

お疲れ様でした。

終わりに
==

非常に簡単なコードを走らせるのにもこれだけボイラープレートが必要なので、正直な話テンプレート様様です。ただ、多くのプロセスを手動でやってみたことでClojurescriptのスタックがどうなっているのかが今までよりもずっと明確に理解できたので、一回やってみるのは有意義なのではないかというのが感想です。

また、この記事で説明した枠組みの中でreagentやfigwheelを追加して使っていけるので、今後そのための手順などの紹介もしていきたいと思います。乞うご期待。