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


TL;DR

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

はじめに

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

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

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

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

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

ちなみにこのIntroduction to ClojureScript and Reagentというビデオに大いに触発されています。
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を開きます。以下のようになっているかと思います。

(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ページから最新版のLeiningen dependency informationをとってきます。
(現在は[org.clojure/clojurescript "1.9.229"]です)

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

:plugins [[lein-cljsbuild "1.1.4"]]

これも最新版をgithubのプロジェクトで調べて使ってください。

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

: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/の下層3つのディレクトリは現時点では存在しないので作成する必要があることに気をつけて下さい。

上記3つの変更を加えて、project.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>
  <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>

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

<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ファイルに置き換えます。その上で、中身も以下のように変えましょう。

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

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

6. コンパイル

lein cljsbuild once dev

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

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

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

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

ちなみにここで私は以下の三種類のミスで失敗したことがあります:
- core.cljcore.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はローカルサーバが返してきた数字を入れてください)

お疲れ様でした。

終わりに

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

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


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