知識0の状態から ClojureScript の周辺環境を理解するまで

## Leiningen をインストールする
(JDKなどJavaの開発環境がインストールされている前提)
Clojure でのプロジェクト管理ツールのデファクトスタンダードである [Leiningen](https://leiningen.org/) をインストールする。

`brew install leiningen` などする。

基本的な使い方は以下が参考になりました。

- http://clojournal.com/tags/leiningen

## emacs の設定
Clojure の開発環境は Emacs が最強らしい。
なので、emacs に [cider](https://github.com/clojure-emacs/cider) をインストールする。

Emacs の環境構築に関して以下を読む。

- http://www.braveclojure.com/basic-emacs/

`~/.lein/profiles.clj` に以下の記述をする。(最新版のciderでは不要のようです。)

```clojure
{:user {:plugins [[cider/cider-nrepl "0.8.1"]]}} 
```

- 基本的な使い方は以下。

```
cider-jack-in で repl に接続する。
C-x C-e (cider-eval-last-expression) で実行
C-c M-n で repl の名前空間を設定
C-c C-k でカレントセッションをコンパイル

C-c M-n    	カレントバッファのnamespaceを切り替える
C-c C-k     	カレントバッファをコンパイル
C-c C-d C-d	カーソルポイントのドキュメント表示
M-. and M-,	Navigate to source code for symbol under point and return to your original buffer.
C-c C-d C-a	Apropros search; find arbitrary text across function names and documentation.

*cider-errpr* は Emacs キーバインドで q で消せる
cider-find-var で def, defn の定義元ジャンプ
C-c C-q で REPL と 関連バッファを消す
```

### IntelliJ IDEA
普段は IntelliJ を使うことが多いので [CurisiveIDE](https://cursive-ide.com/) も考慮に入れる。
emacs の学習コストが高い場合は Cursive でがんばるのも良さそう。

無料版は6ヶ月毎にライセンスキーの更新が必要になる。
仕事で使う場合は有料ライセンスの購入が必要、買い切り型で1年間の無料アップデートできる。


## ClojureScript コンパイラ
基本はClojure公式の [cljs.jar](https://github.com/clojure/clojurescript/releases) を叩いたり Leiningen を使う。
共にClojure製なので、実行に JVM が必要。

最近、NodeJS上で動作する ClojureScriptコンパイラである [lumo](https://github.com/anmonteiro/lumo) というのが出てきた。
これは ClojureScript のソースコードを自分自身で js に変換し、それをNodeJSに載せたものらしい。
lumo によって ClojureScriptが js でセルフホストされたので、JVMの環境を用意しなくても Node があれば ClojureScript を利用することができるようになった。

ただし、lumo が利用している js版の [GoogleClosureCompiler](https://github.com/google/closure-compiler-js) の advancedコンパイルの最適化がJava製のより弱いらしいので、その点を気にするなら今のところは JVM版を使用したほうが良いとのこと。

- lumo の作者のブログエントリ
	- https://anmonteiro.com/2017/02/compiling-clojurescript-projects-without-the-jvm/

## GoogleClosure
ClojureScript は Google Closure Library (GCL)にガッツリ依存している。
細かなエラーは GCL について知っていると解決することが多いらしい。

詳しくは公式サイトを参照のこと。
https://clojurescript.org/about/closure

### ClosureLibrary
ClojureScript は Google の [ClosureLibrary](https://developers.google.com/closure/library/) を組み込みで提供している。
ClojureScript を書いていて何か機能が足りなかったりした場合は、外部ライブラリを探す前に、先に GCL のドキュメントを参照して利用できるものが無いか探してみる。

GCL の機能を把握していると色々と捗るだろう。

### ClosureCompiler
ClojureScript はコンパイル結果のjsを ClosureCompiler を通して最適化する。
開発時などは `:none` や `:simple` を指定してあまり最適化しないかもしれないが、プロダクションビルド時には `:advanced` で積極的な最適化を行うことが推奨されている。

積極的な最適化では、関数のインライン化や変数名のリネーム、デッドコードの削除などを行いビルド後の js のサイズがかなり小さくなるらしい。


## 外部ライブラリの利用
ClojureScript は 当然通常の JavaScript のライブラリを使用できる。
素のJavaScriptのメソッドは以下のように `js/` ネームスペースから呼び出せる。

```clojure
(js/console.log "hello, world")
(.html (js/$ "#cljs-test") "clojure")
```

ただし、このまま ClosureCompiler の積極的な最適化を行うと以下のように実行エラーが発生する。

```
Uncaught TypeError: $(...).Ge is not a function
    at Ni (main.js:320)
    at cljs_entry_point (main.js:320)
    at (index):8
Ni @ main.js:320
cljs_entry_point @ main.js:320
(anonymous) @ (index):8
```

これは、 `$().html` な呼び出し部分が最適化によって `$().Ge` と変換されてしまい、未定義メソッドの呼び出しエラーとなってしまうから。

これを避けるためにはいくつかの方法がある。

- extern ファイルを用意して最適化時にリネームされないようにする
	- https://developers.google.com/closure/compiler/docs/api-tutorial3#externs
- cljsjs リポジトリで用意されている extern ファイルを依存関係に加える
	- http://cljsjs.github.io/
	- よく使われるJavaScriptライブラリの ClojureCompiler用の extern ファイルが用意されている
		- TypeScript でいう DefinitelyTyped のようなもの？

このあたりの対応に関しては、以下の記事がとても参考になりました。
[Advanced Compilation との戦い](http://qiita.com/ayato_p/items/cb86fdc16ac40eaea625)


## React関連ライブラリ
- [reagent](https://github.com/reagent-project/reagent)
	- シンプルなReactラッパーらしい
- [re-frame](https://github.com/Day8/re-frame)
	- reagent の上に作られたフレームワーク
- [Om](https://github.com/omcljs/om)
	- ご存知 CircleCI で[採用](https://github.com/circleci/frontend)されている
	- 独自用語が多く、概念がやや難しいとのこと
		- reagent よりは学習コスト高めらしい
- [rum](https://github.com/tonsky/rum)
	- 最近の流行りらしい
	- reagent より rum のほうがSSRが簡単らしく、SSRやるならこちらが良いのでは、とのこと。

## figwheel
[figwheel](https://github.com/bhauman/lein-figwheel) はモダンな ClojureScript の開発に必須のライブラリ。
cljsの自動コンパイルとホットコードリローディングの機能を提供する。

`lein new figwheel figwheel-sample` などして使い始める。

参考: https://www.youtube.com/watch?v=j-kj2qwJa_E

## 手を動かす
- https://clojurescript.org/guides/quick-start
	- まず読む公式サイトの入門ページ

## 参考になりそうな資料など
- [ClojureScriptチートシート](http://cljs.info/cheatsheet/)
- [ClojureScriptチュートリアル](https://www.niwi.nz/cljs-workshop/)
- [ClojureScript Unraveled](http://funcool.github.io/clojurescript-unraveled/)
- [modern-cljs](https://github.com/magomimmo/modern-cljs)


## その他
- Leiningen重いんだけど
	- -> 落としたら負け
- OracleJDK と OpenJDK
	- Clojure界隈ではOpenJDKがデファクトらしい
- java の知識
	- 環境構築にJVMは必要だけど、lumoとか作れるくらいだし、cljsには必要なさそう
- nREPL
	- https://github.com/clojure/tools.nrepl
	- socket 経由で Clojure のREPLに接続するツール
	- 色々なプラグインや開発環境から利用される
	- Clojureの快適な開発環境は nREPL のおかげらしい

## 謝辞
この記事に書かれている内容の大部分は、勉強会で同席した @iku000888 さんに教えていただきました。
ClojureScript に関して何もわからない状態から、大まかな概要を把握するところまでショートカットすることができました。
ありがとうございました。